diff --git a/sdk/core/azure-core-amqp/CMakeLists.txt b/sdk/core/azure-core-amqp/CMakeLists.txt index 11da287cb6..c2a28d39a3 100644 --- a/sdk/core/azure-core-amqp/CMakeLists.txt +++ b/sdk/core/azure-core-amqp/CMakeLists.txt @@ -171,7 +171,6 @@ set(AZURE_CORE_AMQP_SOURCE src/private/package_version.hpp ) - if (USE_UAMQP) add_library(azure-core-amqp ${AZURE_CORE_AMQP_SOURCE} ${AZURE_CORE_AMQP_HEADER} $) elseif(USE_RUST_AMQP) @@ -193,8 +192,10 @@ target_include_directories( add_library(Azure::azure-core-amqp ALIAS azure-core-amqp) if(USE_UAMQP) +# target_compile_definitions(azure-core-amqp PRIVATE ENABLE_UAMQP) add_compile_definitions(ENABLE_UAMQP) elseif(USE_RUST_AMQP) +# target_compile_definitions(azure-core-amqp PRIVATE ENABLE_RUST_AMQP) add_compile_definitions(ENABLE_RUST_AMQP) endif() @@ -220,10 +221,6 @@ elseif(USE_RUST_AMQP) if (MSVC) target_link_libraries(azure-core-amqp PRIVATE Secur32 ncrypt) endif() -else() - target_link_libraries(azure-core-amqp - PRIVATE - PUBLIC Azure::azure-core) endif() get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp") diff --git a/sdk/core/azure-core-amqp/inc/azure/core/amqp/internal/common/global_state.hpp b/sdk/core/azure-core-amqp/inc/azure/core/amqp/internal/common/global_state.hpp index 9780a2fe4b..08a62c5f1a 100644 --- a/sdk/core/azure-core-amqp/inc/azure/core/amqp/internal/common/global_state.hpp +++ b/sdk/core/azure-core-amqp/inc/azure/core/amqp/internal/common/global_state.hpp @@ -11,11 +11,20 @@ #include #include +#if ENABLE_RUST_AMQP +#include "thread_context.hpp" +#endif + namespace Azure { namespace Core { namespace Amqp { namespace Common { namespace _detail { +#if ENABLE_RUST_AMQP + extern thread_local RustThreadContext RustThreadContextInstance; +#endif + +#if ENABLE_UAMQP /** - * uAMQP and azure-c-shared-util require that the platform_init and platform_uninit functions be - * called before using the various API functions. + * uAMQP and azure-c-shared-util require that the platform_init and platform_uninit + * functions be called before using the various API functions. * * The GlobalState class maintains a singleton static local variable using [static local * variables](https://en.cppreference.com/w/cpp/language/storage_duration#Static_local_variables), @@ -34,15 +43,19 @@ namespace Azure { namespace Core { namespace Amqp { namespace Common { namespace virtual void Poll() = 0; virtual ~Pollable() = default; }; + +#endif class GlobalStateHolder final { GlobalStateHolder(); ~GlobalStateHolder(); +#if ENABLE_UAMQP std::list> m_pollables; std::mutex m_pollablesMutex; std::thread m_pollingThread; std::atomic m_activelyPolling; bool m_stopped{false}; +#endif public: static GlobalStateHolder* GlobalStateInstance(); @@ -53,18 +66,22 @@ namespace Azure { namespace Core { namespace Amqp { namespace Common { namespace GlobalStateHolder(GlobalStateHolder&&) = delete; GlobalStateHolder& operator=(GlobalStateHolder&&) = delete; +#if ENABLE_UAMQP void AddPollable(std::shared_ptr pollable); void RemovePollable(std::shared_ptr pollable); +#endif void AssertIdle() { +#if ENABLE_UAMQP std::lock_guard lock(m_pollablesMutex); AZURE_ASSERT(m_pollables.empty()); if (!m_pollables.empty()) { Azure::Core::_internal::AzureNoReturnPath("Global state is not idle."); } +#endif } }; }}}}} // namespace Azure::Core::Amqp::Common::_detail diff --git a/sdk/core/azure-core-amqp/inc/azure/core/amqp/internal/common/thread_context.hpp b/sdk/core/azure-core-amqp/inc/azure/core/amqp/internal/common/thread_context.hpp new file mode 100644 index 0000000000..c92916b123 --- /dev/null +++ b/sdk/core/azure-core-amqp/inc/azure/core/amqp/internal/common/thread_context.hpp @@ -0,0 +1,50 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#pragma once + +#if ENABLE_RUST_AMQP +#include "../rust_amqp/rust_wrapper/rust_amqp_wrapper.h" +#include "../src/amqp/private/unique_handle.hpp" + +#include + +#include +#include +#include +#include +#include + +namespace Azure { namespace Core { namespace Amqp { namespace _detail { + + using RustRuntimeContext = RustInterop::RuntimeContext; + + template <> struct UniqueHandleHelper + { + static void FreeRuntimeContext(RustRuntimeContext* obj); + + using type = Core::_internal::BasicUniqueHandle; + }; +}}}} // namespace Azure::Core::Amqp::_detail + +namespace Azure { namespace Core { namespace Amqp { namespace Common { namespace _detail { + + using UniqueRustRuntimeContext = Azure::Core::Amqp::_detail::UniqueHandleHelper< + Azure::Core::Amqp::_detail::RustRuntimeContext>::type; + class RustThreadContext final { + + UniqueRustRuntimeContext m_runtimeContext; + + public: + RustThreadContext() + : m_runtimeContext(Azure::Core::Amqp::_detail::RustInterop::runtime_context_new()) + { + } + Azure::Core::Amqp::_detail::RustRuntimeContext* GetRuntimeContext() const noexcept + { + return m_runtimeContext.get(); + } + }; + +}}}}} // namespace Azure::Core::Amqp::Common::_detail +#endif // ENABLE_RUST_AMQP diff --git a/sdk/core/azure-core-amqp/inc/azure/core/amqp/internal/connection.hpp b/sdk/core/azure-core-amqp/inc/azure/core/amqp/internal/connection.hpp index 1c72489ceb..0bf998270b 100644 --- a/sdk/core/azure-core-amqp/inc/azure/core/amqp/internal/connection.hpp +++ b/sdk/core/azure-core-amqp/inc/azure/core/amqp/internal/connection.hpp @@ -24,11 +24,12 @@ namespace Azure { namespace Core { namespace Amqp { namespace _detail { #if defined(_azure_TESTING_BUILD) // Define the test classes dependant on this class here. namespace Azure { namespace Core { namespace Amqp { namespace Tests { +#if ENABLE_UAMQP namespace MessageTests { class AmqpServerMock; class MessageListenerEvents; } // namespace MessageTests - +#endif class TestConnections_ConnectionAttributes_Test; class TestConnections_ConnectionOpenClose_Test; class TestConnections_ConnectionListenClose_Test; @@ -62,6 +63,7 @@ namespace Azure { namespace Core { namespace Amqp { namespace _internal { /** @brief The default port to use to connect to an AMQP server using TLS. */ constexpr uint16_t AmqpTlsPort = 5671; +#if ENABLE_UAMQP /** * @brief The state of the connection. * @@ -205,6 +207,7 @@ namespace Azure { namespace Core { namespace Amqp { namespace _internal { */ virtual bool OnNewEndpoint(Connection const& connection, Endpoint& endpoint) = 0; }; +#endif /** @brief Options used to create a connection. */ struct ConnectionOptions final @@ -262,6 +265,13 @@ namespace Azure { namespace Core { namespace Amqp { namespace _internal { * - desired-capabilities * */ +#if ENABLE_RUST_AMQP + std::vector OutgoingLocales; + std::vector IncomingLocales; + std::vector OfferedCapabilities; + std::vector DesiredCapabilities; + uint32_t BufferSize; +#endif /** @brief Defines the ID of the container for this connection. If empty, a unique 128 bit value * will be used. @@ -275,6 +285,7 @@ namespace Azure { namespace Core { namespace Amqp { namespace _internal { class Connection final { public: +#if ENABLE_UAMQP /** @brief Construct a new AMQP Connection. * * @param hostName The name of the host to connect to. @@ -288,7 +299,21 @@ namespace Azure { namespace Core { namespace Amqp { namespace _internal { std::shared_ptr credential, ConnectionOptions const& options, ConnectionEvents* eventHandler = nullptr); +#else + /** @brief Construct a new AMQP Connection. + * + * @param hostName The name of the host to connect to. + * @param options The options to use when creating the connection. + * + * @remarks The requestUri must be a valid AMQP URI. + */ + Connection( + std::string const& hostName, + std::shared_ptr credential, + ConnectionOptions const& options); +#endif +#if ENABLE_UAMQP /** @brief Construct a new AMQP Connection. * * @param transport The transport to use for the connection. @@ -303,10 +328,12 @@ namespace Azure { namespace Core { namespace Amqp { namespace _internal { ConnectionOptions const& options, ConnectionEvents* eventHandler, ConnectionEndpointEvents* endpointEvents); +#endif /** @brief Destroy an AMQP connection */ ~Connection(); +#if ENABLE_UAMQP /** @brief Create a session on the current Connection object. * * An AMQP Session provides a context for sending and receiving messages. A single connection @@ -318,7 +345,20 @@ namespace Azure { namespace Core { namespace Amqp { namespace _internal { */ Session CreateSession(SessionOptions const& options = {}, SessionEvents* eventHandler = nullptr) const; +#else + /** @brief Create a session on the current Connection object. + * + * An AMQP Session provides a context for sending and receiving messages. A single connection + * may have multiple independent sessions active simultaneously up to the negotiated maximum + * channel count. + * + * @param options The options to use when creating the session. + */ + Session CreateSession(SessionOptions const& options = {}) const; + +#endif +#if ENABLE_UAMQP /** @brief Construct a new session associated with the specified connection over the specified * endpoint. * @@ -335,8 +375,10 @@ namespace Azure { namespace Core { namespace Amqp { namespace _internal { SessionEvents* eventHandler = nullptr) const; void Poll(); - +#endif +#if ENABLE_RUST_AMQP private: +#endif /** @brief Opens the current connection. * * @remarks In general, a customer will not need to call this method, instead the connection @@ -349,6 +391,7 @@ namespace Azure { namespace Core { namespace Amqp { namespace _internal { */ void Open(); +#if ENABLE_UAMQP /** @brief Starts listening for incoming connections. * * @remarks This method should only be called on a connection that was created with a transport @@ -362,6 +405,7 @@ namespace Azure { namespace Core { namespace Amqp { namespace _internal { * the connection, BEFORE destroying it. */ void Listen(); +#endif /** @brief Closes the current connection. * @@ -380,7 +424,9 @@ namespace Azure { namespace Core { namespace Amqp { namespace _internal { std::string const& condition = {}, std::string const& description = {}, Models::AmqpValue info = {}); - +#if ENABLE_RUST_AMQP + private: +#endif /** @brief Gets host configured by the connection. * * @return The host used in the connection. @@ -399,11 +445,13 @@ namespace Azure { namespace Core { namespace Amqp { namespace _internal { */ uint32_t GetMaxFrameSize() const; +#if ENABLE_UAMQP /** @brief Gets the max frame size configured for the remote node. * * @return The configured maximum frame size for the remote node. */ uint32_t GetRemoteMaxFrameSize() const; +#endif /** @brief Gets the max channel count configured for the connection. * @@ -423,6 +471,7 @@ namespace Azure { namespace Core { namespace Amqp { namespace _internal { */ Models::AmqpMap GetProperties() const; +#if ENABLE_UAMQP /** @brief Sets the percentage of the idle timeout before an empty frame is sent to the remote * node. * @@ -440,6 +489,7 @@ namespace Azure { namespace Core { namespace Amqp { namespace _internal { * connection is opened. */ void SetIdleEmptyFrameSendPercentage(double idleTimeoutEmptyFrameSendRatio); +#endif private: /** @brief Create an AMQP Connection from an existing connection implementation. @@ -453,8 +503,10 @@ namespace Azure { namespace Core { namespace Amqp { namespace _internal { std::shared_ptr<_detail::ConnectionImpl> m_impl; friend class _detail::ConnectionFactory; #if _azure_TESTING_BUILD +#if ENABLE_UAMQP friend class Azure::Core::Amqp::Tests::MessageTests::AmqpServerMock; friend class Azure::Core::Amqp::Tests::MessageTests::MessageListenerEvents; +#endif friend class Azure::Core::Amqp::Tests::TestSocketListenerEvents; friend class Azure::Core::Amqp::Tests::LinkSocketListenerEvents; friend class Azure::Core::Amqp::Tests::TestConnections_ConnectionAttributes_Test; @@ -468,8 +520,10 @@ namespace Azure { namespace Core { namespace Amqp { namespace _internal { friend class Azure::Core::Amqp::Tests::TestMessages_SenderOpenClose_Test; #endif // _azure_TESTING_BUILD +#if ENABLE_UAMQP #if SAMPLES_BUILD friend int LocalServerSample::LocalServerSampleMain(); #endif // SAMPLES_BUILD +#endif }; }}}} // namespace Azure::Core::Amqp::_internal diff --git a/sdk/core/azure-core-amqp/inc/azure/core/amqp/internal/connection_string_credential.hpp b/sdk/core/azure-core-amqp/inc/azure/core/amqp/internal/connection_string_credential.hpp index b06c977aa7..1212b7a2bd 100644 --- a/sdk/core/azure-core-amqp/inc/azure/core/amqp/internal/connection_string_credential.hpp +++ b/sdk/core/azure-core-amqp/inc/azure/core/amqp/internal/connection_string_credential.hpp @@ -130,12 +130,14 @@ namespace Azure { namespace Core { namespace Amqp { namespace _internal { */ std::string GetAudience(); +#if ENABLE_UAMQP /** @brief Return a SASL transport configured for SASL Anonymous which will be used to * communicate with the AMQP service. * * @return A SASL transport configured for SASL Anonymous. */ virtual std::shared_ptr GetTransport() const; +#endif std::string const& GetEndpoint() const { return m_connectionParser.GetEndpoint(); } std::string const& GetSharedAccessKeyName() const diff --git a/sdk/core/azure-core-amqp/inc/azure/core/amqp/internal/link.hpp b/sdk/core/azure-core-amqp/inc/azure/core/amqp/internal/link.hpp index e2692f4923..57c32f9efc 100644 --- a/sdk/core/azure-core-amqp/inc/azure/core/amqp/internal/link.hpp +++ b/sdk/core/azure-core-amqp/inc/azure/core/amqp/internal/link.hpp @@ -97,8 +97,13 @@ namespace Azure { namespace Core { namespace Amqp { namespace _detail { std::string const& name, _internal::SessionRole role, Models::_internal::MessageSource const& source, - Models::_internal::MessageTarget const& target, - LinkEvents* events = nullptr); + Models::_internal::MessageTarget const& target +#if ENABLE_UAMQP + , + LinkEvents* events = nullptr +#endif + ); +#if ENABLE_UAMQP Link( _internal::Session const& session, _internal::LinkEndpoint& linkEndpoint, @@ -107,6 +112,7 @@ namespace Azure { namespace Core { namespace Amqp { namespace _detail { Models::_internal::MessageSource const& source, Models::_internal::MessageTarget const& target, LinkEvents* events = nullptr); +#endif ~Link() noexcept; Link(Link const&) = default; diff --git a/sdk/core/azure-core-amqp/inc/azure/core/amqp/internal/network/amqp_header_detect_transport.hpp b/sdk/core/azure-core-amqp/inc/azure/core/amqp/internal/network/amqp_header_detect_transport.hpp index 125f32349f..a9a7b9ce52 100644 --- a/sdk/core/azure-core-amqp/inc/azure/core/amqp/internal/network/amqp_header_detect_transport.hpp +++ b/sdk/core/azure-core-amqp/inc/azure/core/amqp/internal/network/amqp_header_detect_transport.hpp @@ -3,6 +3,7 @@ #pragma once +#if ENABLE_UAMQP #include "transport.hpp" #include @@ -28,3 +29,5 @@ namespace Azure { namespace Core { namespace Amqp { namespace Network { namespac }; }}}}} // namespace Azure::Core::Amqp::Network::_internal + +#endif diff --git a/sdk/core/azure-core-amqp/inc/azure/core/amqp/internal/network/sasl_transport.hpp b/sdk/core/azure-core-amqp/inc/azure/core/amqp/internal/network/sasl_transport.hpp index 3c7b6bbad4..bb07d6a0e4 100644 --- a/sdk/core/azure-core-amqp/inc/azure/core/amqp/internal/network/sasl_transport.hpp +++ b/sdk/core/azure-core-amqp/inc/azure/core/amqp/internal/network/sasl_transport.hpp @@ -3,10 +3,10 @@ #pragma once +#if ENABLE_UAMQP #include "transport.hpp" #include - namespace Azure { namespace Core { namespace Amqp { namespace Network { namespace _internal { /** @brief Factory to create a transport using SASL authentication. @@ -47,3 +47,4 @@ namespace Azure { namespace Core { namespace Amqp { namespace Network { namespac }; }}}}} // namespace Azure::Core::Amqp::Network::_internal +#endif diff --git a/sdk/core/azure-core-amqp/inc/azure/core/amqp/internal/network/socket_listener.hpp b/sdk/core/azure-core-amqp/inc/azure/core/amqp/internal/network/socket_listener.hpp index 57401991d6..9ea8e6200f 100644 --- a/sdk/core/azure-core-amqp/inc/azure/core/amqp/internal/network/socket_listener.hpp +++ b/sdk/core/azure-core-amqp/inc/azure/core/amqp/internal/network/socket_listener.hpp @@ -3,6 +3,7 @@ #pragma once +#if ENABLE_UAMQP #include "transport.hpp" #include @@ -10,10 +11,8 @@ #include #include -#if ENABLE_UAMQP struct SOCKET_LISTENER_INSTANCE_TAG; struct IO_INTERFACE_DESCRIPTION_TAG; -#endif namespace Azure { namespace Core { namespace Amqp { namespace Network { namespace _detail { @@ -36,17 +35,14 @@ namespace Azure { namespace Core { namespace Amqp { namespace Network { namespac void Poll() const; private: -#if ENABLE_UAMQP static void OnSocketAcceptedFn( void* context, const IO_INTERFACE_DESCRIPTION_TAG* interfaceDescription, void* io_parameters); -#endif std::atomic_bool m_started{false}; SocketListenerEvents* m_eventHandler{}; -#if ENABLE_UAMQP SOCKET_LISTENER_INSTANCE_TAG* m_socket; -#endif }; }}}}} // namespace Azure::Core::Amqp::Network::_detail +#endif diff --git a/sdk/core/azure-core-amqp/inc/azure/core/amqp/internal/network/socket_transport.hpp b/sdk/core/azure-core-amqp/inc/azure/core/amqp/internal/network/socket_transport.hpp index 2c789cdd25..a11e561ba6 100644 --- a/sdk/core/azure-core-amqp/inc/azure/core/amqp/internal/network/socket_transport.hpp +++ b/sdk/core/azure-core-amqp/inc/azure/core/amqp/internal/network/socket_transport.hpp @@ -3,6 +3,7 @@ #pragma once +#if ENABLE_UAMQP #include "transport.hpp" #include @@ -33,3 +34,4 @@ namespace Azure { namespace Core { namespace Amqp { namespace Network { namespac }; }}}}} // namespace Azure::Core::Amqp::Network::_internal +#endif diff --git a/sdk/core/azure-core-amqp/inc/azure/core/amqp/internal/network/tls_transport.hpp b/sdk/core/azure-core-amqp/inc/azure/core/amqp/internal/network/tls_transport.hpp index 7d30f5a77d..775d89008d 100644 --- a/sdk/core/azure-core-amqp/inc/azure/core/amqp/internal/network/tls_transport.hpp +++ b/sdk/core/azure-core-amqp/inc/azure/core/amqp/internal/network/tls_transport.hpp @@ -3,6 +3,8 @@ #pragma once +#if ENABLE_UAMQP + #include "transport.hpp" #include @@ -29,3 +31,4 @@ namespace Azure { namespace Core { namespace Amqp { namespace Network { namespac TlsTransportFactory() = delete; }; }}}}} // namespace Azure::Core::Amqp::Network::_internal +#endif diff --git a/sdk/core/azure-core-amqp/inc/azure/core/amqp/internal/network/transport.hpp b/sdk/core/azure-core-amqp/inc/azure/core/amqp/internal/network/transport.hpp index e818438e81..59572f9d39 100644 --- a/sdk/core/azure-core-amqp/inc/azure/core/amqp/internal/network/transport.hpp +++ b/sdk/core/azure-core-amqp/inc/azure/core/amqp/internal/network/transport.hpp @@ -5,6 +5,7 @@ // Licensed under the MIT License. #pragma once +#if ENABLE_UAMQP #include #include @@ -137,3 +138,4 @@ namespace Azure { namespace Core { namespace Amqp { namespace Network { namespac std::shared_ptr<_detail::TransportImpl> m_impl; }; }}}}} // namespace Azure::Core::Amqp::Network::_internal +#endif diff --git a/sdk/core/azure-core-amqp/inc/azure/core/amqp/internal/session.hpp b/sdk/core/azure-core-amqp/inc/azure/core/amqp/internal/session.hpp index 93c7e40054..f3d809e1a0 100644 --- a/sdk/core/azure-core-amqp/inc/azure/core/amqp/internal/session.hpp +++ b/sdk/core/azure-core-amqp/inc/azure/core/amqp/internal/session.hpp @@ -127,6 +127,7 @@ namespace Azure { namespace Core { namespace Amqp { namespace _internal { /** @brief Destroys the session object. */ ~Session() noexcept; +#if ENABLE_UAMQP /** @brief Creates a MessageSender * * @param target - The target to which the message will be sent. @@ -139,7 +140,20 @@ namespace Azure { namespace Core { namespace Amqp { namespace _internal { MessageSender CreateMessageSender( Models::_internal::MessageTarget const& target, MessageSenderOptions const& options, - MessageSenderEvents* events) const; + MessageSenderEvents* events = nullptr) const; +#elif ENABLE_RUST_AMQP + /** @brief Creates a MessageSender + * + * @param target - The target to which the message will be sent. + * @param options - Options to configure the MessageSender. + * + * @returns A MessageSender object. + * + */ + MessageSender CreateMessageSender( + Models::_internal::MessageTarget const& target, + MessageSenderOptions const& options) const; +#endif /** @brief Creates a MessageReceiver * @@ -222,11 +236,13 @@ namespace Azure { namespace Core { namespace Amqp { namespace _internal { * use by AMQP listeners. * */ +#if ENABLE_UAMQP MessageSender CreateMessageSender( LinkEndpoint& endpoint, Models::_internal::MessageTarget const& target, MessageSenderOptions const& options, - MessageSenderEvents* events) const; + MessageSenderEvents* events = nullptr) const; +#endif /** @brief Creates a MessageReceiver for use in a message listener. * diff --git a/sdk/core/azure-core-amqp/rust_amqp/azure_core_amqp/Cargo.toml b/sdk/core/azure-core-amqp/rust_amqp/azure_core_amqp/Cargo.toml index 080bef1c29..23f7987d40 100644 --- a/sdk/core/azure-core-amqp/rust_amqp/azure_core_amqp/Cargo.toml +++ b/sdk/core/azure-core-amqp/rust_amqp/azure_core_amqp/Cargo.toml @@ -18,12 +18,10 @@ categories = ["api-bindings"] edition = "2021" [dependencies] -async-std = { workspace = true } -azure_core = { workspace = true } -time = { workspace = true } -tracing = { workspace = true } -url = { workspace = true } -uuid = { workspace = true } +async-std.workspace = true +azure_core.workspace = true +time.workspace = true +tracing.workspace = true fe2o3-amqp = { workspace = true, optional = true } fe2o3-amqp-ext = { workspace = true, optional = true } fe2o3-amqp-management = { workspace = true, optional = true } @@ -31,6 +29,7 @@ fe2o3-amqp-cbs = { workspace = true, optional = true } fe2o3-amqp-types = { workspace = true, optional = true } serde_amqp = { workspace = true, optional = true } serde_bytes = { workspace = true, optional = true } +uuid = { workspace = true } [dev-dependencies] tracing-subscriber = { workspace = true, features = ["env-filter"] } diff --git a/sdk/core/azure-core-amqp/rust_amqp/azure_core_amqp/src/connection.rs b/sdk/core/azure-core-amqp/rust_amqp/azure_core_amqp/src/connection.rs index 133ca4d0ac..898c2a532e 100644 --- a/sdk/core/azure-core-amqp/rust_amqp/azure_core_amqp/src/connection.rs +++ b/sdk/core/azure-core-amqp/rust_amqp/azure_core_amqp/src/connection.rs @@ -3,10 +3,9 @@ // cspell: words amqp sasl use super::value::{AmqpOrderedMap, AmqpSymbol, AmqpValue}; -use azure_core::error::Result; +use azure_core::{error::Result, Url}; use std::fmt::Debug; use time::Duration; -use url::Url; #[cfg(all(feature = "fe2o3-amqp", not(target_arch = "wasm32")))] type ConnectionImplementation = super::fe2o3::connection::Fe2o3AmqpConnection; @@ -14,7 +13,7 @@ type ConnectionImplementation = super::fe2o3::connection::Fe2o3AmqpConnection; #[cfg(any(not(feature = "fe2o3-amqp"), target_arch = "wasm32"))] type ConnectionImplementation = super::noop::NoopAmqpConnection; -#[derive(Debug, Default)] +#[derive(Debug, Default, Clone)] pub struct AmqpConnectionOptions { pub(crate) max_frame_size: Option, pub(crate) channel_max: Option, @@ -31,6 +30,34 @@ impl AmqpConnectionOptions { pub fn builder() -> builders::AmqpConnectionOptionsBuilder { builders::AmqpConnectionOptionsBuilder::new() } + + pub fn max_frame_size(&self) -> Option { + self.max_frame_size + } + pub fn channel_max(&self) -> Option { + self.channel_max + } + pub fn idle_timeout(&self) -> Option { + self.idle_timeout + } + pub fn outgoing_locales(&self) -> Option> { + self.outgoing_locales.clone() + } + pub fn incoming_locales(&self) -> Option> { + self.incoming_locales.clone() + } + pub fn offered_capabilities(&self) -> Option> { + self.offered_capabilities.clone() + } + pub fn desired_capabilities(&self) -> Option> { + self.desired_capabilities.clone() + } + pub fn properties(&self) -> Option> { + self.properties.clone() + } + pub fn buffer_size(&self) -> Option { + self.buffer_size + } } pub trait AmqpConnectionApis { @@ -41,6 +68,12 @@ pub trait AmqpConnectionApis { options: Option, ) -> impl std::future::Future>; fn close(&self) -> impl std::future::Future>; + fn close_with_error( + &self, + condition: impl Into, + description: Option, + info: Option>, + ) -> impl std::future::Future>; } #[derive(Debug, Default)] @@ -60,6 +93,15 @@ impl AmqpConnectionApis for AmqpConnection { fn close(&self) -> impl std::future::Future> { self.implementation.close() } + fn close_with_error( + &self, + condition: impl Into, + description: Option, + info: Option>, + ) -> impl std::future::Future> { + self.implementation + .close_with_error(condition, description, info) + } } impl AmqpConnection { @@ -82,45 +124,47 @@ pub mod builders { options: Default::default(), } } - pub fn build(self) -> AmqpConnectionOptions { - self.options + pub fn build(&mut self) -> AmqpConnectionOptions { + self.options.clone() } - #[allow(dead_code)] - pub fn with_max_frame_size(mut self, max_frame_size: u32) -> Self { + pub fn with_max_frame_size(&mut self, max_frame_size: u32) -> &mut Self { self.options.max_frame_size = Some(max_frame_size); self } - #[allow(dead_code)] - pub fn with_channel_max(mut self, channel_max: u16) -> Self { + pub fn with_channel_max(&mut self, channel_max: u16) -> &mut Self { self.options.channel_max = Some(channel_max); self } - #[allow(dead_code)] - pub fn with_idle_timeout(mut self, idle_timeout: Duration) -> Self { + pub fn with_idle_timeout(&mut self, idle_timeout: Duration) -> &mut Self { self.options.idle_timeout = Some(idle_timeout); self } - #[allow(dead_code)] - pub fn with_outgoing_locales(mut self, outgoing_locales: Vec) -> Self { + pub fn with_outgoing_locales(&mut self, outgoing_locales: Vec) -> &mut Self { self.options.outgoing_locales = Some(outgoing_locales); self } - #[allow(dead_code)] - pub fn with_incoming_locales(mut self, incoming_locales: Vec) -> Self { + pub fn with_incoming_locales(&mut self, incoming_locales: Vec) -> &mut Self { self.options.incoming_locales = Some(incoming_locales); self } - #[allow(dead_code)] - pub fn with_offered_capabilities(mut self, offered_capabilities: Vec) -> Self { + pub fn with_offered_capabilities( + &mut self, + offered_capabilities: Vec, + ) -> &mut Self { self.options.offered_capabilities = Some(offered_capabilities); self } - #[allow(dead_code)] - pub fn with_desired_capabilities(mut self, desired_capabilities: Vec) -> Self { + pub fn with_desired_capabilities( + &mut self, + desired_capabilities: Vec, + ) -> &mut Self { self.options.desired_capabilities = Some(desired_capabilities); self } - pub fn with_properties(mut self, properties: impl Into>) -> Self + pub fn with_properties( + &mut self, + properties: impl Into>, + ) -> &mut Self where K: Into + Debug + Default + PartialEq, V: Into + Debug + Default, @@ -133,8 +177,7 @@ pub mod builders { self.options.properties = Some(properties_map); self } - #[allow(dead_code)] - pub fn with_buffer_size(mut self, buffer_size: usize) -> Self { + pub fn with_buffer_size(&mut self, buffer_size: usize) -> &mut Self { self.options.buffer_size = Some(buffer_size); self } diff --git a/sdk/core/azure-core-amqp/rust_amqp/azure_core_amqp/src/fe2o3/connection.rs b/sdk/core/azure-core-amqp/rust_amqp/azure_core_amqp/src/fe2o3/connection.rs index 45504b1310..d59c30c76a 100644 --- a/sdk/core/azure-core-amqp/rust_amqp/azure_core_amqp/src/fe2o3/connection.rs +++ b/sdk/core/azure-core-amqp/rust_amqp/azure_core_amqp/src/fe2o3/connection.rs @@ -3,13 +3,13 @@ // cspell: words amqp sasl use crate::connection::{AmqpConnectionApis, AmqpConnectionOptions}; +use crate::value::{AmqpOrderedMap, AmqpSymbol, AmqpValue}; use async_std::sync::Mutex; -use azure_core::Result; +use azure_core::{Result, Url}; use fe2o3_amqp::connection::ConnectionHandle; use std::{borrow::BorrowMut, sync::OnceLock}; use tracing::debug; -use url::Url; use super::error::{AmqpConnection, AmqpOpen}; @@ -118,4 +118,24 @@ impl AmqpConnectionApis for Fe2o3AmqpConnection { .map_err(AmqpConnection::from)?; Ok(()) } + async fn close_with_error( + &self, + condition: impl Into, + description: Option, + info: Option>, + ) -> Result<()> { + let mut connection = self.connection.get().unwrap().lock().await; + connection + .borrow_mut() + .close_with_error(fe2o3_amqp::types::definitions::Error::new( + fe2o3_amqp::types::definitions::ErrorCondition::Custom( + fe2o3_amqp_types::primitives::Symbol::from(condition.into()), + ), + description, + info.map(|i| i.into()), + )) + .await + .map_err(AmqpConnection::from)?; + Ok(()) + } } diff --git a/sdk/core/azure-core-amqp/rust_amqp/azure_core_amqp/src/fe2o3/messaging/message_fields.rs b/sdk/core/azure-core-amqp/rust_amqp/azure_core_amqp/src/fe2o3/messaging/message_fields.rs index 51433ca8a7..a0c7f4895f 100644 --- a/sdk/core/azure-core-amqp/rust_amqp/azure_core_amqp/src/fe2o3/messaging/message_fields.rs +++ b/sdk/core/azure-core-amqp/rust_amqp/azure_core_amqp/src/fe2o3/messaging/message_fields.rs @@ -50,7 +50,8 @@ impl From for fe2o3_amqp_types::messaging::MessageId { #[test] fn test_message_id_conversion() { - use uuid::Uuid; + use crate::Uuid; + { let message_id = fe2o3_amqp_types::messaging::MessageId::String("test".into()); let amqp_message_id: AmqpMessageId = message_id.clone().into(); diff --git a/sdk/core/azure-core-amqp/rust_amqp/azure_core_amqp/src/fe2o3/value.rs b/sdk/core/azure-core-amqp/rust_amqp/azure_core_amqp/src/fe2o3/value.rs index a2b965b5ee..5eda27df70 100644 --- a/sdk/core/azure-core-amqp/rust_amqp/azure_core_amqp/src/fe2o3/value.rs +++ b/sdk/core/azure-core-amqp/rust_amqp/azure_core_amqp/src/fe2o3/value.rs @@ -2,14 +2,12 @@ // Licensed under the MIT license. // cspell: words amqp -use serde_bytes::ByteBuf; -use std::time::UNIX_EPOCH; - -use serde_amqp::primitives::Timestamp; - use crate::value::{ AmqpDescribed, AmqpDescriptor, AmqpList, AmqpOrderedMap, AmqpSymbol, AmqpTimestamp, AmqpValue, }; +use serde_amqp::primitives::Timestamp; +use serde_bytes::ByteBuf; +use std::time::UNIX_EPOCH; impl From for AmqpSymbol { fn from(s: fe2o3_amqp_types::primitives::Symbol) -> AmqpSymbol { @@ -511,6 +509,7 @@ impl From for crate::Receiver #[cfg(test)] mod tests { use super::*; + use crate::Uuid; #[test] fn test_from_fe2o3_amqp_types_primitives_symbol() { @@ -677,7 +676,7 @@ mod tests { } { - let uuid = uuid::Uuid::new_v4(); + let uuid = Uuid::new_v4(); let fe2o3 = fe2o3_amqp_types::primitives::Value::Uuid(uuid.into()); let amqp: AmqpValue = fe2o3.clone().into(); let fe2o3_2: fe2o3_amqp_types::primitives::Value = amqp.clone().into(); diff --git a/sdk/core/azure-core-amqp/rust_amqp/azure_core_amqp/src/lib.rs b/sdk/core/azure-core-amqp/rust_amqp/azure_core_amqp/src/lib.rs index fee091ab3a..b55723b49f 100644 --- a/sdk/core/azure-core-amqp/rust_amqp/azure_core_amqp/src/lib.rs +++ b/sdk/core/azure-core-amqp/rust_amqp/azure_core_amqp/src/lib.rs @@ -16,6 +16,8 @@ pub mod sender; pub mod session; pub mod value; +pub type Uuid = uuid::Uuid; + use std::fmt::Debug; // AMQP Settle mode: diff --git a/sdk/core/azure-core-amqp/rust_amqp/azure_core_amqp/src/messaging.rs b/sdk/core/azure-core-amqp/rust_amqp/azure_core_amqp/src/messaging.rs index 09914be848..c9503e9b57 100644 --- a/sdk/core/azure-core-amqp/rust_amqp/azure_core_amqp/src/messaging.rs +++ b/sdk/core/azure-core-amqp/rust_amqp/azure_core_amqp/src/messaging.rs @@ -7,7 +7,9 @@ use super::value::{AmqpList, AmqpOrderedMap, AmqpSymbol, AmqpTimestamp, AmqpValu use crate::Deserializable; #[cfg(feature = "cplusplus")] use azure_core::error::ErrorKind; -use azure_core::error::Result; +use azure_core::Result; + +use crate::Uuid; #[derive(Debug, Clone, PartialEq)] pub enum TerminusDurability { @@ -116,13 +118,13 @@ impl From for AmqpOutcome { #[derive(Debug, Clone, PartialEq)] pub enum AmqpMessageId { String(String), - Uuid(uuid::Uuid), + Uuid(Uuid), Binary(Vec), Ulong(u64), } -impl From for AmqpMessageId { - fn from(uuid: uuid::Uuid) -> Self { +impl From for AmqpMessageId { + fn from(uuid: Uuid) -> Self { AmqpMessageId::Uuid(uuid) } } @@ -1531,7 +1533,6 @@ mod tests { use super::*; use fe2o3_amqp_types::messaging::Priority; use std::time::SystemTime; - use uuid::Uuid; #[test] fn test_amqp_message_header_builder() { diff --git a/sdk/core/azure-core-amqp/rust_amqp/azure_core_amqp/src/noop.rs b/sdk/core/azure-core-amqp/rust_amqp/azure_core_amqp/src/noop.rs index 49110d1a10..9be56d80b1 100644 --- a/sdk/core/azure-core-amqp/rust_amqp/azure_core_amqp/src/noop.rs +++ b/sdk/core/azure-core-amqp/rust_amqp/azure_core_amqp/src/noop.rs @@ -11,7 +11,7 @@ use super::{ receiver::{AmqpReceiverApis, AmqpReceiverOptions}, sender::{AmqpSendOptions, AmqpSenderApis, AmqpSenderOptions}, session::{AmqpSession, AmqpSessionApis, AmqpSessionOptions}, - value::{AmqpOrderedMap, AmqpValue}, + value::{AmqpOrderedMap, AmqpSymbol, AmqpValue}, }; use azure_core::{auth::AccessToken, error::Result}; @@ -42,7 +42,7 @@ impl AmqpConnectionApis for NoopAmqpConnection { async fn open( &self, name: impl Into, - url: url::Url, + url: azure_core::Url, options: Option, ) -> Result<()> { unimplemented!() @@ -50,6 +50,15 @@ impl AmqpConnectionApis for NoopAmqpConnection { async fn close(&self) -> Result<()> { unimplemented!() } + + async fn close_with_error( + &self, + condition: impl Into, + description: Option, + info: Option>, + ) -> impl Result<()> { + unimplemented!() + } } impl NoopAmqpSession { diff --git a/sdk/core/azure-core-amqp/rust_amqp/azure_core_amqp/src/value.rs b/sdk/core/azure-core-amqp/rust_amqp/azure_core_amqp/src/value.rs index 3e1af33540..cc8126d4f3 100644 --- a/sdk/core/azure-core-amqp/rust_amqp/azure_core_amqp/src/value.rs +++ b/sdk/core/azure-core-amqp/rust_amqp/azure_core_amqp/src/value.rs @@ -2,11 +2,11 @@ // Licensed under the MIT license. // cspell: words amqp -#[cfg(feature = "cplusplus")] -use azure_core::Result; - +use crate::Uuid; #[cfg(feature = "cplusplus")] use crate::{Deserializable, Serializable}; +#[cfg(feature = "cplusplus")] +use azure_core::Result; #[derive(Debug, PartialEq, Clone, Default, Eq)] pub struct AmqpSymbol(pub String); @@ -171,7 +171,7 @@ pub enum AmqpValue { Double(f64), Char(char), TimeStamp(AmqpTimestamp), - Uuid(uuid::Uuid), + Uuid(Uuid), Binary(Vec), String(String), Symbol(AmqpSymbol), @@ -345,7 +345,7 @@ conversions_for_amqp_types!( (f32, Float), (f64, Double), (char, Char), - (uuid::Uuid, Uuid), + (Uuid, Uuid), (Vec, Binary), (std::string::String, String), (AmqpSymbol, Symbol), @@ -445,13 +445,13 @@ where #[cfg(test)] mod tests { - use std::vec; - use super::*; + use std::vec; + use Uuid; #[test] fn test_value_create_specific() { - let uuid = uuid::Uuid::new_v4(); + let uuid = Uuid::new_v4(); let timestamp = std::time::SystemTime::now(); let v1 = AmqpValue::Boolean(true); let v2 = AmqpValue::UByte(1); @@ -561,7 +561,7 @@ mod tests { TimeStamp, AmqpTimestamp(std::time::SystemTime::now()) ); - test_conversion!(uuid::Uuid, Uuid, uuid::Uuid::new_v4()); + test_conversion!(Uuid, Uuid, Uuid::new_v4()); test_conversion!(Vec, Binary, vec![1, 2, 3]); test_conversion!(String, String, "hello".to_string()); test_conversion!(AmqpSymbol, Symbol, AmqpSymbol("hello".to_string())); @@ -729,11 +729,11 @@ mod tests { assert_eq!(timestamp_val, AmqpTimestamp(timestamp)); // Test AmqpValue::Uuid - let uuid = uuid::Uuid::new_v4(); + let uuid = Uuid::new_v4(); let uuid_value: AmqpValue = AmqpValue::Uuid(uuid); assert_eq!(uuid_value, AmqpValue::Uuid(uuid)); assert_eq!(AmqpValue::Uuid(uuid), uuid_value); - let uuid_val: uuid::Uuid = uuid_value.into(); + let uuid_val: Uuid = uuid_value.into(); assert_eq!(uuid_val, uuid); // Test AmqpValue::Binary diff --git a/sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/Cargo.toml b/sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/Cargo.toml index cdc8d7155f..b23a74e250 100644 --- a/sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/Cargo.toml +++ b/sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/Cargo.toml @@ -14,10 +14,14 @@ crate-type = ["staticlib"] [dependencies] azure_core_amqp = { workspace = true, features = ["cplusplus"] } -azure_identity = { workspace = true } -azure_core = { workspace = true } -uuid = { workspace = true } -tracing = { workspace = true } +azure_identity.workspace = true +azure_core.workspace = true +uuid.workspace = true +tracing.workspace = true +tracing-subscriber.workspace = true +tokio.workspace = true +url.workspace = true +time.workspace = true [dev-dependencies] serde_amqp = { workspace = true } diff --git a/sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/build.rs b/sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/build.rs index eb3c2dc3a6..369975749e 100644 --- a/sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/build.rs +++ b/sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/build.rs @@ -19,16 +19,10 @@ fn main() { config.structure = struct_config; config.language = Language::Cxx; config.namespaces = Some( - vec![ - "Azure", - "Core", - "Amqp", - "_detail", - "RustInterop", - ] - .iter() - .map(|x| x.to_string()) - .collect(), + vec!["Azure", "Core", "Amqp", "_detail", "RustInterop"] + .iter() + .map(|x| x.to_string()) + .collect(), ); config.cpp_compat = true; config.autogen_warning = Some( @@ -36,19 +30,21 @@ fn main() { .to_string(), ); config.header = Some( - "/* Copyright (c) Microsoft Corp. All Rights Reserved. + "/* Copyright (c) Microsoft Corp. All Rights Reserved. * Licensed under the MIT License. **/ // cspell: words cbindgen amqp amqpvalue - #pragma once - ".to_string()); + " + .to_string(), + ); cbindgen::Builder::new() .with_crate(crate_dir) .with_namespace("ffi") .with_std_types(true) .with_config(config) + .with_pragma_once(true) .generate() .expect("Unable to generate C++ bindings.") .write_to_file("rust_amqp_wrapper.h"); diff --git a/sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/src/amqp/connection.rs b/sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/src/amqp/connection.rs new file mode 100644 index 0000000000..1ea03bd598 --- /dev/null +++ b/sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/src/amqp/connection.rs @@ -0,0 +1,571 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. +// Licensed under the MIT License. +// cspell: words amqp amqpconnection amqpconnectionoptionsbuilder amqpconnectionoptions + +use core::panic; +use std::{ + ffi::{c_char, CStr}, + mem, + ptr::{self, null}, +}; +use time::Duration; + +use crate::{ + model::value::RustAmqpValue, + runtime_context::{runtime_context_from_ptr_mut, RuntimeContext}, +}; + +use tracing::error; +use url::Url; + +use azure_core_amqp::{ + connection::{ + builders::AmqpConnectionOptionsBuilder, AmqpConnection, AmqpConnectionApis, + AmqpConnectionOptions, + }, + value::{AmqpOrderedMap, AmqpSymbol, AmqpValue}, +}; + +pub struct RustAmqpConnection { + inner: AmqpConnection, +} + +pub struct RustAmqpConnectionOptionsBuilder { + inner: AmqpConnectionOptionsBuilder, +} + +pub struct RustAmqpConnectionOptions { + inner: AmqpConnectionOptions, +} + +#[no_mangle] +pub extern "C" fn amqpconnection_create() -> *mut RustAmqpConnection { + Box::into_raw(Box::new(RustAmqpConnection { + inner: AmqpConnection::new(), + })) +} + +#[no_mangle] +pub extern "C" fn amqpconnection_destroy(connection: *mut RustAmqpConnection) { + unsafe { + mem::drop(Box::from_raw(connection)); + } +} + +#[no_mangle] +pub extern "C" fn amqpconnection_open( + ctx: *mut RuntimeContext, + connection: *const RustAmqpConnection, + url: *const c_char, + container_id: *const c_char, + options: *const RustAmqpConnectionOptions, +) -> u32 { + let runtime_context = runtime_context_from_ptr_mut(ctx); + let connection = unsafe { &*connection }; + let url = unsafe { CStr::from_ptr(url) }; + let url = url.to_str(); + let container_id = unsafe { CStr::from_ptr(container_id) }; + let default_options: RustAmqpConnectionOptions = RustAmqpConnectionOptions { + inner: Default::default(), + }; + let options = if options != null() { + unsafe { &*options } + } else { + &default_options + }; + + if url.is_err() { + error!("Failed to convert URL to string: {:?}", url.err()); + runtime_context.set_error(url.err().unwrap().into()); + return 1; + } + let url = url.unwrap(); + + let url = Url::parse(url); + if url.is_err() { + let err = url.err().unwrap(); + error!("Failed to parse URL: {:?}", &err); + runtime_context.set_error(err.into()); + return 1; + } + let url = url.unwrap(); + + let result = runtime_context.runtime().block_on(connection.inner.open( + container_id.to_str().unwrap(), + url, + Some(options.inner.clone()), + )); + match result { + Ok(_) => 0, + Err(err) => { + error!("Failed to open connection: {:?}", err); + runtime_context.set_error(err.into()); + 1 + } + } +} + +#[no_mangle] +pub extern "C" fn amqpconnection_close( + ctx: *mut RuntimeContext, + connection: *const RustAmqpConnection, +) -> u32 { + let connection = unsafe { &*connection }; + let runtime_context = runtime_context_from_ptr_mut(ctx); + let result = runtime_context.runtime().block_on(connection.inner.close()); + match result { + Ok(_) => 0, + Err(err) => { + error!("Failed to close connection: {:?}", err); + runtime_context.set_error(err.into()); + 1 + } + } +} + +#[no_mangle] +pub extern "C" fn amqpconnection_close_with_error( + ctx: *mut RuntimeContext, + connection: *const RustAmqpConnection, + condition: *const c_char, + description: *const c_char, + info: *const RustAmqpValue, +) -> u32 { + let connection = unsafe { &*connection }; + let runtime_context = runtime_context_from_ptr_mut(ctx); + let condition = unsafe { CStr::from_ptr(condition) }; + let description = unsafe { CStr::from_ptr(description) }; + let info = unsafe { &*info }; + if let AmqpValue::Map(info) = &info.inner { + let info: AmqpOrderedMap = info + .clone() + .into_iter() + .map(|f| { + ( + match f.0 { + AmqpValue::Symbol(s) => s, + _ => panic!("Expected symbol"), + }, + f.1, + ) + }) + .collect(); + let result = runtime_context + .runtime() + .block_on(connection.inner.close_with_error( + condition.to_str().unwrap(), + Some(description.to_str().unwrap().into()), + Some(info.clone()), + )); + match result { + Ok(_) => 0, + Err(err) => { + error!("Failed to close connection with error: {:?}", err); + runtime_context.set_error(err.into()); + 1 + } + } + } else { + 1 + } +} + +#[no_mangle] +pub extern "C" fn amqpconnectionoptions_get_idle_timeout( + options: *const RustAmqpConnectionOptions, +) -> u32 { + let options = unsafe { &*options }; + if let Some(timeout) = options.inner.idle_timeout() { + return timeout.whole_milliseconds() as u32; + } + 0 +} + +#[no_mangle] +pub extern "C" fn amqpconnectionoptions_get_max_frame_size( + options: *const RustAmqpConnectionOptions, +) -> u32 { + let options = unsafe { &*options }; + if let Some(max_frame_size) = options.inner.max_frame_size() { + return max_frame_size; + } + 0 +} + +#[no_mangle] +pub extern "C" fn amqpconnectionoptions_get_channel_max( + options: *const RustAmqpConnectionOptions, +) -> u16 { + let options = unsafe { &*options }; + if let Some(channel_max) = options.inner.channel_max() { + return channel_max; + } + 0 +} + +#[no_mangle] +pub extern "C" fn amqpconnectionoptions_get_properties( + options: *const RustAmqpConnectionOptions, +) -> *mut RustAmqpValue { + let options = unsafe { &*options }; + let properties = options.inner.properties(); + if let Some(properties) = properties { + let properties: AmqpOrderedMap = properties + .into_iter() + .map(|f| (AmqpValue::Symbol(f.0.clone()), f.1.clone())) + .collect(); + Box::into_raw(Box::new(RustAmqpValue { + inner: AmqpValue::Map(properties), + })) + } else { + ptr::null_mut() + } +} + +#[no_mangle] +pub extern "C" fn amqpconnectionoptionsbuilder_create() -> *mut RustAmqpConnectionOptionsBuilder { + let builder = AmqpConnectionOptions::builder(); + Box::into_raw(Box::new(RustAmqpConnectionOptionsBuilder { + inner: builder, + })) +} + +#[no_mangle] +pub extern "C" fn amqpconnectionoptionsbuilder_destroy( + builder: *mut RustAmqpConnectionOptionsBuilder, +) { + unsafe { + mem::drop(Box::from_raw(builder)); + } +} + +#[no_mangle] +pub extern "C" fn amqpconnectionoptionsbuilder_build( + builder: *mut RustAmqpConnectionOptionsBuilder, +) -> *mut RustAmqpConnectionOptions { + let builder = unsafe { &mut *builder }; + let options = builder.inner.build(); + Box::into_raw(Box::new(RustAmqpConnectionOptions { inner: options })) +} + +#[no_mangle] +pub extern "C" fn amqpconnectionoptions_destroy(options: *mut RustAmqpConnectionOptions) { + unsafe { + mem::drop(Box::from_raw(options)); + } +} + +#[no_mangle] +pub extern "C" fn amqpconnectionoptionsbuilder_set_idle_timeout( + builder: *mut RustAmqpConnectionOptionsBuilder, + idle_timeout: u32, +) -> u32 { + let builder = unsafe { &mut *builder }; + builder + .inner + .with_idle_timeout(Duration::milliseconds(idle_timeout as i64)); + 0 +} + +#[no_mangle] +pub extern "C" fn amqpconnectionoptionsbuilder_set_max_frame_size( + builder: *mut RustAmqpConnectionOptionsBuilder, + max_frame_size: u32, +) -> u32 { + let builder = unsafe { &mut *builder }; + builder.inner.with_max_frame_size(max_frame_size); + 0 +} + +#[no_mangle] +pub extern "C" fn amqpconnectionoptionsbuilder_set_channel_max( + builder: *mut RustAmqpConnectionOptionsBuilder, + channel_max: u16, +) -> u32 { + let builder = unsafe { &mut *builder }; + builder.inner.with_channel_max(channel_max); + 0 +} + +#[no_mangle] +pub extern "C" fn amqpconnectionoptionsbuilder_set_outgoing_locales( + builder: *mut RustAmqpConnectionOptionsBuilder, + locales: *const *const c_char, + count: usize, +) -> u32 { + let builder = unsafe { &mut *builder }; + let locales = unsafe { std::slice::from_raw_parts(locales, count) }; + let locales = locales + .iter() + .map(|locale| unsafe { CStr::from_ptr(*locale).to_str().unwrap() }) + .collect::>(); + builder + .inner + .with_outgoing_locales(locales.into_iter().map(String::from).collect()); + 0 +} + +#[no_mangle] +pub extern "C" fn amqpconnectionoptionsbuilder_set_incoming_locales( + builder: *mut RustAmqpConnectionOptionsBuilder, + locales: *const *const c_char, + count: usize, +) -> u32 { + let builder = unsafe { &mut *builder }; + let locales = unsafe { std::slice::from_raw_parts(locales, count) }; + let locales = locales + .iter() + .map(|locale| unsafe { CStr::from_ptr(*locale).to_str().unwrap() }) + .collect::>(); + builder + .inner + .with_incoming_locales(locales.into_iter().map(String::from).collect()); + 0 +} + +#[no_mangle] +pub extern "C" fn amqpconnectionoptionsbuilder_set_offered_capabilities( + builder: *mut RustAmqpConnectionOptionsBuilder, + capabilities: *const *const c_char, + count: usize, +) -> u32 { + let builder = unsafe { &mut *builder }; + let capabilities = unsafe { std::slice::from_raw_parts(capabilities, count) }; + let capabilities = capabilities + .iter() + .map(|capability| unsafe { CStr::from_ptr(*capability).to_str().unwrap() }) + .collect::>(); + builder + .inner + .with_offered_capabilities(capabilities.into_iter().map(AmqpSymbol::from).collect()); + 0 +} + +#[no_mangle] +pub extern "C" fn amqpconnectionoptionsbuilder_set_desired_capabilities( + builder: *mut RustAmqpConnectionOptionsBuilder, + capabilities: *const *const c_char, + count: usize, +) -> u32 { + let builder = unsafe { &mut *builder }; + let capabilities = unsafe { std::slice::from_raw_parts(capabilities, count) }; + let capabilities = capabilities + .iter() + .map(|capability| unsafe { CStr::from_ptr(*capability).to_str().unwrap() }) + .collect::>(); + builder + .inner + .with_desired_capabilities(capabilities.into_iter().map(AmqpSymbol::from).collect()); + 0 +} + +#[no_mangle] +pub extern "C" fn amqpconnectionoptionsbuilder_set_properties( + builder: *mut RustAmqpConnectionOptionsBuilder, + properties: *const RustAmqpValue, +) -> u32 { + let builder = unsafe { &mut *builder }; + let properties = unsafe { &*properties }; + match &properties.inner { + AmqpValue::Map(properties) => { + let properties: AmqpOrderedMap = properties + .clone() + .into_iter() + .map(|f| { + ( + match f.0 { + AmqpValue::Symbol(s) => s, + _ => panic!("Expected symbol"), + }, + f.1, + ) + }) + .collect(); + builder.inner.with_properties(properties); + 0 + } + _ => 1, + } +} + +#[no_mangle] +pub extern "C" fn amqpconnectionoptionsbuilder_set_buffer_size( + builder: *mut RustAmqpConnectionOptionsBuilder, + buffer_size: usize, +) -> u32 { + let builder = unsafe { &mut *builder }; + builder.inner.with_buffer_size(buffer_size); + 0 +} + +#[cfg(test)] +mod tests { + use super::*; + use std::ffi::CString; + use std::ptr; + + fn create_runtime_context() -> *mut RuntimeContext { + // Mock implementation for creating a runtime context + Box::into_raw(Box::new(RuntimeContext::new().unwrap())) + } + + #[test] + fn test_amqpconnection_create_and_destroy() { + let connection = amqpconnection_create(); + assert!(!connection.is_null()); + amqpconnection_destroy(connection); + } + + #[test] + fn test_amqpconnection_open_and_close() { + let ctx = create_runtime_context(); + let connection = amqpconnection_create(); + let url = CString::new("amqp://localhost:25672").unwrap(); + let container_id = CString::new("test_container").unwrap(); + let options = ptr::null(); + + let open_result = amqpconnection_open( + ctx, + connection, + url.as_ptr(), + container_id.as_ptr(), + options, + ); + assert_eq!(open_result, 0); + + let close_result = amqpconnection_close(ctx, connection); + assert_eq!(close_result, 0); + + amqpconnection_destroy(connection); + } + + #[test] + fn test_amqpconnectionoptionsbuilder_create_and_destroy() { + let builder = amqpconnectionoptionsbuilder_create(); + assert!(!builder.is_null()); + amqpconnectionoptionsbuilder_destroy(builder); + } + + #[test] + fn test_amqpconnectionoptionsbuilder_set_idle_timeout() { + let builder = amqpconnectionoptionsbuilder_create(); + let result = amqpconnectionoptionsbuilder_set_idle_timeout(builder, 30); + assert_eq!(result, 0); + amqpconnectionoptionsbuilder_destroy(builder); + } + + #[test] + fn test_amqpconnectionoptionsbuilder_set_max_frame_size() { + let builder = amqpconnectionoptionsbuilder_create(); + let result = amqpconnectionoptionsbuilder_set_max_frame_size(builder, 65536); + assert_eq!(result, 0); + amqpconnectionoptionsbuilder_destroy(builder); + } + + #[test] + fn test_amqpconnectionoptionsbuilder_set_channel_max() { + let builder = amqpconnectionoptionsbuilder_create(); + let result = amqpconnectionoptionsbuilder_set_channel_max(builder, 256); + assert_eq!(result, 0); + amqpconnectionoptionsbuilder_destroy(builder); + } + + #[test] + fn test_amqpconnectionoptionsbuilder_set_outgoing_locales() { + let builder = amqpconnectionoptionsbuilder_create(); + let locales = vec![ + CString::new("en-US").unwrap(), + CString::new("fr-FR").unwrap(), + ]; + let locale_ptrs: Vec<*const c_char> = + locales.iter().map(|locale| locale.as_ptr()).collect(); + let result = amqpconnectionoptionsbuilder_set_outgoing_locales( + builder, + locale_ptrs.as_ptr(), + locale_ptrs.len(), + ); + assert_eq!(result, 0); + amqpconnectionoptionsbuilder_destroy(builder); + } + + #[test] + fn test_amqpconnectionoptionsbuilder_set_incoming_locales() { + let builder = amqpconnectionoptionsbuilder_create(); + let locales = vec![ + CString::new("en-US").unwrap(), + CString::new("fr-FR").unwrap(), + ]; + let locale_ptrs: Vec<*const c_char> = + locales.iter().map(|locale| locale.as_ptr()).collect(); + let result = amqpconnectionoptionsbuilder_set_incoming_locales( + builder, + locale_ptrs.as_ptr(), + locale_ptrs.len(), + ); + assert_eq!(result, 0); + amqpconnectionoptionsbuilder_destroy(builder); + } + + #[test] + fn test_amqpconnectionoptionsbuilder_set_offered_capabilities() { + let builder = amqpconnectionoptionsbuilder_create(); + let capabilities = vec![ + CString::new("capability1").unwrap(), + CString::new("capability2").unwrap(), + ]; + let capability_ptrs: Vec<*const c_char> = + capabilities.iter().map(|cap| cap.as_ptr()).collect(); + let result = amqpconnectionoptionsbuilder_set_offered_capabilities( + builder, + capability_ptrs.as_ptr(), + capability_ptrs.len(), + ); + assert_eq!(result, 0); + amqpconnectionoptionsbuilder_destroy(builder); + } + + #[test] + fn test_amqpconnectionoptionsbuilder_set_desired_capabilities() { + let builder = amqpconnectionoptionsbuilder_create(); + let capabilities = vec![ + CString::new("capability1").unwrap(), + CString::new("capability2").unwrap(), + ]; + let capability_ptrs: Vec<*const c_char> = + capabilities.iter().map(|cap| cap.as_ptr()).collect(); + let result = amqpconnectionoptionsbuilder_set_desired_capabilities( + builder, + capability_ptrs.as_ptr(), + capability_ptrs.len(), + ); + assert_eq!(result, 0); + amqpconnectionoptionsbuilder_destroy(builder); + } + + #[test] + fn test_amqpconnectionoptionsbuilder_set_properties() { + let builder = amqpconnectionoptionsbuilder_create(); + let mut map: AmqpOrderedMap = AmqpOrderedMap::new(); + map.insert(AmqpSymbol::from("key1"), AmqpValue::from("value1")); + map.insert(AmqpSymbol::from("key2"), AmqpValue::from("value2")); + + let rust_value = RustAmqpValue { + inner: AmqpValue::Map(map.into_iter().map(|f| (f.0.into(), f.1)).collect()), + }; + + let result = amqpconnectionoptionsbuilder_set_properties( + builder, + &rust_value as *const RustAmqpValue, + ); + assert_eq!(result, 0); + amqpconnectionoptionsbuilder_destroy(builder); + } + + #[test] + fn test_amqpconnectionoptionsbuilder_set_buffer_size() { + let builder = amqpconnectionoptionsbuilder_create(); + let result = amqpconnectionoptionsbuilder_set_buffer_size(builder, 1024); + assert_eq!(result, 0); + amqpconnectionoptionsbuilder_destroy(builder); + } +} diff --git a/sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/src/amqp/mod.rs b/sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/src/amqp/mod.rs new file mode 100644 index 0000000000..8e4b64b522 --- /dev/null +++ b/sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/src/amqp/mod.rs @@ -0,0 +1,4 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. +// Licensed under the MIT License. + +pub mod connection; diff --git a/sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/src/lib.rs b/sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/src/lib.rs index 3804aaa3b5..f2f3a78a0a 100644 --- a/sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/src/lib.rs +++ b/sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/src/lib.rs @@ -1,19 +1,20 @@ // Copyright (c) Microsoft Corporation. All Rights Reserved. // Licensed under the MIT License. +// cspell: words amqp + #![crate_type = "staticlib"] use std::{ ffi::{c_char, CString}, mem, }; -pub mod header; -pub mod message; -pub mod message_fields; -pub mod properties; -pub mod source; -pub mod target; -pub mod value; + +pub mod amqp; +pub mod model; +pub mod runtime_context; +pub mod rust_error; +pub mod tracing; #[no_mangle] pub extern "C" fn rust_string_delete(rust_string: *const c_char) { diff --git a/sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/src/header.rs b/sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/src/model/header.rs similarity index 98% rename from sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/src/header.rs rename to sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/src/model/header.rs index d8c620fa26..617e9cb1d3 100644 --- a/sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/src/header.rs +++ b/sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/src/model/header.rs @@ -9,7 +9,7 @@ use azure_core_amqp::{ }; use std::mem; -use crate::value::RustAmqpValue; +use super::value::RustAmqpValue; pub struct RustMessageHeader { inner: AmqpMessageHeader, @@ -202,7 +202,7 @@ mod tests { use azure_core_amqp::Deserializable; - use crate::value::{amqpvalue_encode, amqpvalue_get_encoded_size}; + use crate::model::value::{amqpvalue_encode, amqpvalue_get_encoded_size}; use super::*; diff --git a/sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/src/message.rs b/sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/src/model/message.rs similarity index 99% rename from sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/src/message.rs rename to sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/src/model/message.rs index 583fbbdc12..3cb18f068c 100644 --- a/sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/src/message.rs +++ b/sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/src/model/message.rs @@ -3,7 +3,9 @@ // cspell: words amqp amqpvalue repr -use crate::{header::RustMessageHeader, properties::RustMessageProperties, value::RustAmqpValue}; +use crate::model::{ + header::RustMessageHeader, properties::RustMessageProperties, value::RustAmqpValue, +}; use azure_core_amqp::{ messaging::{ AmqpAnnotationKey, AmqpAnnotations, AmqpApplicationProperties, AmqpMessage, AmqpMessageBody, diff --git a/sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/src/message_fields.rs b/sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/src/model/message_fields.rs similarity index 98% rename from sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/src/message_fields.rs rename to sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/src/model/message_fields.rs index 5e3cfa2d9d..f2317fa91c 100644 --- a/sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/src/message_fields.rs +++ b/sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/src/model/message_fields.rs @@ -3,7 +3,7 @@ // cspell: words amqp amqpvalue repr -use crate::value::RustAmqpValue; +use crate::model::value::RustAmqpValue; use azure_core_amqp::value::{AmqpDescribed, AmqpValue}; #[no_mangle] diff --git a/sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/src/model/mod.rs b/sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/src/model/mod.rs new file mode 100644 index 0000000000..b0f41dd1a4 --- /dev/null +++ b/sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/src/model/mod.rs @@ -0,0 +1,10 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. +// Licensed under the MIT License. + +pub mod header; +pub mod message; +pub mod message_fields; +pub mod properties; +pub mod source; +pub mod target; +pub mod value; diff --git a/sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/src/properties.rs b/sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/src/model/properties.rs similarity index 99% rename from sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/src/properties.rs rename to sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/src/model/properties.rs index 7d1391c2f1..c8be821cdb 100644 --- a/sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/src/properties.rs +++ b/sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/src/model/properties.rs @@ -10,7 +10,7 @@ use azure_core_amqp::{ use std::mem; use std::time::UNIX_EPOCH; -use crate::value::RustAmqpValue; +use crate::model::value::RustAmqpValue; pub struct RustMessageProperties { pub(crate) inner: AmqpMessageProperties, diff --git a/sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/src/source.rs b/sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/src/model/source.rs similarity index 99% rename from sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/src/source.rs rename to sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/src/model/source.rs index f98726263b..787e598a04 100644 --- a/sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/src/source.rs +++ b/sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/src/model/source.rs @@ -3,7 +3,7 @@ // cspell: words amqp amqpvalue repr -use crate::value::RustAmqpValue; +use crate::model::value::RustAmqpValue; use azure_core_amqp::{ messaging::{builders::AmqpSourceBuilder, AmqpSource}, value::{AmqpComposite, AmqpDescriptor, AmqpOrderedMap, AmqpSymbol, AmqpValue}, diff --git a/sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/src/target.rs b/sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/src/model/target.rs similarity index 99% rename from sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/src/target.rs rename to sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/src/model/target.rs index 6bc74a193f..92716a5316 100644 --- a/sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/src/target.rs +++ b/sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/src/model/target.rs @@ -8,7 +8,7 @@ use azure_core_amqp::{ value::{AmqpDescribed, AmqpDescriptor, AmqpList, AmqpOrderedMap, AmqpValue}, }; -use crate::{ +use crate::model::{ source::{RustExpiryPolicy, RustTerminusDurability}, value::RustAmqpValue, }; diff --git a/sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/src/value.rs b/sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/src/model/value.rs similarity index 100% rename from sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/src/value.rs rename to sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/src/model/value.rs diff --git a/sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/src/runtime_context.rs b/sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/src/runtime_context.rs new file mode 100644 index 0000000000..0ff8ee6ad7 --- /dev/null +++ b/sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/src/runtime_context.rs @@ -0,0 +1,132 @@ +// Copyright (c) Microsoft Corp. All Rights Reserved +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// cspell: words reqwest repr tokio + +use crate::rust_error::RustError; +use azure_core::{error::ErrorKind, Error, Result}; +use std::mem; + +#[derive(Debug)] +pub struct RuntimeContext { + runtime: tokio::runtime::Runtime, + error: Option, +} + +impl RuntimeContext { + pub fn new() -> Result { + Ok(Self { + // runtime: match tokio::runtime::Builder::new_current_thread() + runtime: match tokio::runtime::Builder::new_multi_thread() + .enable_all() + .build() + .map_err(|err| Error::new(ErrorKind::Other, err)) + { + Ok(it) => it, + Err(err) => return Err(err), + }, + error: None, + }) + } + + pub fn set_error(&mut self, error: Error) { + self.error = Some(error); + } + + pub fn runtime(&self) -> &tokio::runtime::Runtime { + &self.runtime + } +} + +#[no_mangle] +pub extern "C" fn runtime_context_new() -> *mut RuntimeContext { + match RuntimeContext::new() { + Ok(ctx) => Box::into_raw(Box::new(ctx)), + Err(_) => std::ptr::null_mut(), + } +} + +#[no_mangle] +pub extern "C" fn runtime_context_get_error(ctx: *const RuntimeContext) -> *mut RustError { + let ctx = unsafe { &*ctx }; + match &ctx.error { + Some(err) => { + let msg = format!("{:?}", err); + Box::into_raw(Box::new(RustError::new(Error::message( + err.kind().clone(), + msg, + )))) + .cast() + } + None => std::ptr::null::().cast_mut(), + } +} + +#[no_mangle] +pub unsafe extern "C" fn runtime_context_delete(ctx: *mut RuntimeContext) { + mem::drop(Box::from_raw(ctx)) +} + +pub(crate) fn runtime_context_from_ptr<'a>(ctx: *const RuntimeContext) -> &'a RuntimeContext { + unsafe { &*ctx } +} +pub(crate) fn runtime_context_from_ptr_mut<'a>(ctx: *mut RuntimeContext) -> &'a mut RuntimeContext { + unsafe { &mut *ctx } +} + +#[test] +fn test_runtime_context_new() { + let ctx = runtime_context_new(); + assert_ne!(ctx, std::ptr::null_mut()); + unsafe { + runtime_context_delete(ctx); + } +} + +#[test] +fn test_runtime_context_get_error() { + let ctx = runtime_context_new(); + assert_ne!(ctx, std::ptr::null_mut()); + let error = runtime_context_get_error(ctx); + assert_eq!(error, std::ptr::null_mut()); + unsafe { + runtime_context_delete(ctx); + } +} + +#[test] +fn test_runtime_context_delete() { + let ctx = runtime_context_new(); + assert_ne!(ctx, std::ptr::null_mut()); + unsafe { + runtime_context_delete(ctx); + } +} + +#[test] +fn test_runtime_context_from_ptr() { + let ctx = runtime_context_new(); + assert_ne!(ctx, std::ptr::null_mut()); + let _ctx_from_ptr = runtime_context_from_ptr(ctx); + unsafe { + runtime_context_delete(ctx as *mut RuntimeContext); + } +} + +#[test] +fn test_runtime_context_from_ptr_mut() { + let ctx = runtime_context_new(); + assert_ne!(ctx, std::ptr::null_mut()); + let _ctx_from_ptr = runtime_context_from_ptr_mut(ctx); + unsafe { + runtime_context_delete(ctx); + } +} + +#[test] +fn test_runtime_context_set_error() { + let mut ctx = RuntimeContext::new().unwrap(); + ctx.set_error(Error::new(ErrorKind::Other, "test")); + let error = runtime_context_get_error(&ctx); + assert_ne!(error, std::ptr::null_mut()); +} diff --git a/sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/src/rust_error.rs b/sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/src/rust_error.rs new file mode 100644 index 0000000000..d200b683f0 --- /dev/null +++ b/sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/src/rust_error.rs @@ -0,0 +1,29 @@ +// Copyright (c) Microsoft Corp. All Rights Reserved +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/* +cspell: words reqwest repr staticlib dylib brotli gzip +*/ + +pub struct RustError(azure_core::Error); + +impl RustError { + pub fn new(error: azure_core::Error) -> Self { + RustError(error) + } +} + +#[no_mangle] +pub extern "C" fn rust_error_get_message(error: *const RustError) -> *mut i8 { + let error = unsafe { error.as_ref().unwrap() }; + let message = error.0.to_string(); + let c_message = std::ffi::CString::new(message).unwrap(); + c_message.into_raw() +} + +#[no_mangle] +pub extern "C" fn rust_error_delete(error: *mut RustError) { + unsafe { + let _ = Box::from_raw(error); + } +} diff --git a/sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/src/tracing.rs b/sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/src/tracing.rs new file mode 100644 index 0000000000..56aa1d53d5 --- /dev/null +++ b/sdk/core/azure-core-amqp/rust_amqp/rust_wrapper/src/tracing.rs @@ -0,0 +1,51 @@ +// Copyright (c) Microsoft Corp. All Rights Reserved +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/* +cspell: words reqwest repr staticlib dylib brotli gzip +*/ + +use std::{ + ffi::{c_char, CString}, + fmt::Debug, +}; + +struct RustTracingSubscriber { + tracing_callback: Option, +} + +impl RustTracingSubscriber { + fn new() -> Self { + Self { + tracing_callback: None, + } + } + + fn set_tracing_callback(&mut self, callback: extern "C" fn(_: *const c_char)) { + self.tracing_callback = Some(callback); + } + + fn on_event(&self, message: &str) { + if let Some(callback) = self.tracing_callback { + let c_message = CString::new(message).unwrap(); + callback(c_message.as_ptr()); + } + } +} + +impl Debug for RustTracingSubscriber { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("RustTracingSubscriber") + .field("tracing_callback", &self.tracing_callback.is_some()) + .finish() + } +} + +#[no_mangle] +pub extern "C" fn register_tracing_callback(callback: extern "C" fn(_: *const c_char)) { + let message = CString::new("register_tracing_callback").unwrap(); + callback(message.as_ptr()); +} + +#[no_mangle] +pub extern "C" fn unregister_tracing_callback() {} diff --git a/sdk/core/azure-core-amqp/samples/internal/CMakeLists.txt b/sdk/core/azure-core-amqp/samples/internal/CMakeLists.txt index 676cd577be..d3ff0f91f9 100644 --- a/sdk/core/azure-core-amqp/samples/internal/CMakeLists.txt +++ b/sdk/core/azure-core-amqp/samples/internal/CMakeLists.txt @@ -7,7 +7,9 @@ cmake_minimum_required (VERSION 3.13) # Include sub-projects. +if(USE_UAMQP) add_subdirectory ("local_server_sample") +endif() add_subdirectory ("local_client_sample") add_subdirectory ("local_client_async_sample") #add_subdirectory ("eventhub_writer_sample") diff --git a/sdk/core/azure-core-amqp/samples/internal/eventhub_sas_writer_sample/eventhub_sas_writer_sample.cpp b/sdk/core/azure-core-amqp/samples/internal/eventhub_sas_writer_sample/eventhub_sas_writer_sample.cpp index 172ba58a28..ea26163df1 100644 --- a/sdk/core/azure-core-amqp/samples/internal/eventhub_sas_writer_sample/eventhub_sas_writer_sample.cpp +++ b/sdk/core/azure-core-amqp/samples/internal/eventhub_sas_writer_sample/eventhub_sas_writer_sample.cpp @@ -45,8 +45,14 @@ int main() senderOptions.MessageSource = "ingress"; senderOptions.SettleMode = Azure::Core::Amqp::_internal::SenderSettleMode::Settled; senderOptions.MaxMessageSize = (std::numeric_limits::max)(); - Azure::Core::Amqp::_internal::MessageSender sender( - session.CreateMessageSender(entityPath, senderOptions, nullptr)); + Azure::Core::Amqp::_internal::MessageSender sender(session.CreateMessageSender( + entityPath, + senderOptions +#if ENABLE_UAMQP + , + nullptr +#endif + )); // Open the connection to the remote. if (auto err = sender.Open()) diff --git a/sdk/core/azure-core-amqp/samples/internal/eventhub_token_writer_sample/eventhub_token_writer_sample.cpp b/sdk/core/azure-core-amqp/samples/internal/eventhub_token_writer_sample/eventhub_token_writer_sample.cpp index 93e4977644..43d59e289f 100644 --- a/sdk/core/azure-core-amqp/samples/internal/eventhub_token_writer_sample/eventhub_token_writer_sample.cpp +++ b/sdk/core/azure-core-amqp/samples/internal/eventhub_token_writer_sample/eventhub_token_writer_sample.cpp @@ -58,7 +58,7 @@ int main() senderOptions.SettleMode = Azure::Core::Amqp::_internal::SenderSettleMode::Settled; senderOptions.EnableTrace = true; Azure::Core::Amqp::_internal::MessageSender sender( - session.CreateMessageSender(eventhubsEntity, senderOptions, nullptr)); + session.CreateMessageSender(eventhubsEntity, senderOptions)); // Open the connection to the remote. This will authenticate the client and connect to the server. if (auto err = sender.Open()) diff --git a/sdk/core/azure-core-amqp/samples/internal/local_client_async_sample/local_client_async_sample.cpp b/sdk/core/azure-core-amqp/samples/internal/local_client_async_sample/local_client_async_sample.cpp index 539660570f..f21136de5b 100644 --- a/sdk/core/azure-core-amqp/samples/internal/local_client_async_sample/local_client_async_sample.cpp +++ b/sdk/core/azure-core-amqp/samples/internal/local_client_async_sample/local_client_async_sample.cpp @@ -28,7 +28,7 @@ int main() senderOptions.MessageSource = "ingress"; senderOptions.MaxMessageSize = (std::numeric_limits::max)(); Azure::Core::Amqp::_internal::MessageSender sender{ - session.CreateMessageSender("localhost/ingress", senderOptions, nullptr)}; + session.CreateMessageSender("localhost/ingress", senderOptions)}; // Open the connection to the remote. if (sender.Open()) diff --git a/sdk/core/azure-core-amqp/samples/internal/local_client_sample/local_client_sample.cpp b/sdk/core/azure-core-amqp/samples/internal/local_client_sample/local_client_sample.cpp index 383f941ad3..4aa6096df7 100644 --- a/sdk/core/azure-core-amqp/samples/internal/local_client_sample/local_client_sample.cpp +++ b/sdk/core/azure-core-amqp/samples/internal/local_client_sample/local_client_sample.cpp @@ -27,7 +27,7 @@ int main() senderOptions.MessageSource = "ingress"; senderOptions.MaxMessageSize = (std::numeric_limits::max)(); Azure::Core::Amqp::_internal::MessageSender sender{ - session.CreateMessageSender("localhost/ingress", senderOptions, nullptr)}; + session.CreateMessageSender("localhost/ingress", senderOptions)}; // Open the connection to the remote. if (auto err = sender.Open()) diff --git a/sdk/core/azure-core-amqp/src/amqp/connection.cpp b/sdk/core/azure-core-amqp/src/amqp/connection.cpp index fd4c5202c7..1bf8fa4848 100644 --- a/sdk/core/azure-core-amqp/src/amqp/connection.cpp +++ b/sdk/core/azure-core-amqp/src/amqp/connection.cpp @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +// cspell: words amqpconnection amqpconnectionoptions amqpconnectionoptionsbuilder + #include "azure/core/amqp/internal/connection.hpp" #include "../models/private/value_impl.hpp" @@ -19,15 +21,34 @@ #if ENABLE_UAMQP #include +#elif ENABLE_RUST_AMQP +using namespace Azure::Core::Amqp::_detail::RustInterop; #endif #include namespace Azure { namespace Core { namespace Amqp { namespace _detail { -#if ENABLE_UAMQP - void UniqueHandleHelper::FreeAmqpConnection(CONNECTION_HANDLE value) + void UniqueHandleHelper::FreeAmqpConnection( + AmqpConnectionImplementation* value) { +#if ENABLE_UAMQP connection_destroy(value); +#elif ENABLE_RUST_AMQP + amqpconnection_destroy(value); +#endif + } +#if ENABLE_RUST_AMQP + void UniqueHandleHelper::FreeAmqpConnectionOptions( + AmqpConnectionOptionsImplementation* value) + { + amqpconnectionoptions_destroy(value); + } + + void + UniqueHandleHelper::FreeAmqpConnectionOptionsBuilder( + AmqpConnectionOptionsBuilderImplementation* value) + { + amqpconnectionoptionsbuilder_destroy(value); } #endif }}}} // namespace Azure::Core::Amqp::_detail @@ -38,6 +59,7 @@ using namespace Azure::Core::Diagnostics; namespace Azure { namespace Core { namespace Amqp { namespace _internal { // Create a connection with an existing networking Transport. +#if ENABLE_UAMQP Connection::Connection( Network::_internal::Transport const& transport, ConnectionOptions const& options, @@ -51,15 +73,30 @@ namespace Azure { namespace Core { namespace Amqp { namespace _internal { { m_impl->FinishConstruction(); } +#endif // Create a connection with a request URI and options. Connection::Connection( std::string const& hostName, std::shared_ptr credential, - ConnectionOptions const& options, - ConnectionEvents* eventHandler) - : m_impl{ - std::make_shared<_detail::ConnectionImpl>(hostName, credential, options, eventHandler)} + ConnectionOptions const& options +#if ENABLE_UAMQP + , + ConnectionEvents* eventHandler +#endif + ) + : m_impl + { + std::make_shared<_detail::ConnectionImpl>( + hostName, + credential, + options +#if ENABLE_UAMQP + , + eventHandler +#endif + ) + } { m_impl->FinishConstruction(); } @@ -67,13 +104,25 @@ namespace Azure { namespace Core { namespace Amqp { namespace _internal { Connection::~Connection() {} Session Connection::CreateSession( - SessionOptions const& sessionOptions, - SessionEvents* sessionEvents) const + SessionOptions const& sessionOptions +#if ENABLE_UAMQP + , + SessionEvents* sessionEvents +#endif + ) const { return Azure::Core::Amqp::_detail::SessionFactory::CreateFromInternal( - std::make_shared<_detail::SessionImpl>(m_impl, sessionOptions, sessionEvents)); + std::make_shared<_detail::SessionImpl>( + m_impl, + sessionOptions +#if ENABLE_UAMQP + , + sessionEvents +#endif + )); } +#if ENABLE_UAMQP Session Connection::CreateSession( Endpoint& endpoint, SessionOptions const& sessionOptions, @@ -82,10 +131,10 @@ namespace Azure { namespace Core { namespace Amqp { namespace _internal { return Azure::Core::Amqp::_detail::SessionFactory::CreateFromInternal( std::make_shared<_detail::SessionImpl>(m_impl, endpoint, sessionOptions, sessionEvents)); } - void Connection::Poll() { m_impl->Poll(); } void Connection::Listen() { m_impl->Listen(); } +#endif // ENABLE_UAMQP void Connection::Open() { m_impl->Open(); } void Connection::Close( std::string const& condition, @@ -95,16 +144,21 @@ namespace Azure { namespace Core { namespace Amqp { namespace _internal { m_impl->Close(condition, description, value); } uint32_t Connection::GetMaxFrameSize() const { return m_impl->GetMaxFrameSize(); } +#if ENABLE_UAMQP uint32_t Connection::GetRemoteMaxFrameSize() const { return m_impl->GetRemoteMaxFrameSize(); } +#endif uint16_t Connection::GetMaxChannel() const { return m_impl->GetMaxChannel(); } std::string Connection::GetHost() const { return m_impl->GetHost(); } uint16_t Connection::GetPort() const { return m_impl->GetPort(); } std::chrono::milliseconds Connection::GetIdleTimeout() const { return m_impl->GetIdleTimeout(); } Models::AmqpMap Connection::GetProperties() const { return m_impl->GetProperties(); } +#if ENABLE_UAMQP void Connection::SetIdleEmptyFrameSendPercentage(double ratio) { m_impl->SetIdleEmptyFrameSendPercentage(ratio); } +#endif +#if ENABLE_UAMQP std::ostream& operator<<(std::ostream& stream, ConnectionState state) { switch (state) @@ -157,7 +211,7 @@ namespace Azure { namespace Core { namespace Amqp { namespace _internal { } return stream; } - +#endif }}}} // namespace Azure::Core::Amqp::_internal namespace { @@ -174,6 +228,7 @@ void EnsureGlobalStateInitialized() namespace Azure { namespace Core { namespace Amqp { namespace _detail { // Create a connection with an existing networking Transport. +#if ENABLE_UAMQP ConnectionImpl::ConnectionImpl( std::shared_ptr transport, _internal::ConnectionOptions const& options, @@ -185,18 +240,33 @@ namespace Azure { namespace Core { namespace Amqp { namespace _detail { EnsureGlobalStateInitialized(); m_transport = transport; } +#endif // Create a connection with a request URI and options. ConnectionImpl::ConnectionImpl( std::string const& hostName, std::shared_ptr credential, - _internal::ConnectionOptions const& options, - _internal::ConnectionEvents* eventHandler) - : m_hostName{hostName}, m_port{options.Port}, m_options{options}, - m_eventHandler{eventHandler}, m_credential{credential} + _internal::ConnectionOptions const& options +#if ENABLE_UAMQP + , + _internal::ConnectionEvents* eventHandler +#endif + ) + : +#if ENABLE_UAMQP + m_hostName{hostName}, m_port{options.Port}, +#elif ENABLE_RUST_AMQP + m_connection{amqpconnection_create()}, +#endif + m_options{options}, +#if ENABLE_UAMQP + m_eventHandler{eventHandler}, +#endif + m_credential{credential} { EnsureGlobalStateInitialized(); +#if ENABLE_UAMQP if (options.Port == _internal::AmqpPort) { Log::Write(Logger::Level::Informational, "Creating socket connection transport."); @@ -215,6 +285,29 @@ namespace Azure { namespace Core { namespace Amqp { namespace _detail { m_transport = Network::_internal::SocketTransportFactory::Create(m_hostName, m_port).GetImpl(); } +#elif ENABLE_RUST_AMQP + std::string connectionUrl; + uint16_t port = options.Port; + if (port == _internal::AmqpPort) + { + connectionUrl = "amqp://"; + } + else if (port == _internal::AmqpTlsPort) + { + connectionUrl = "amqps://"; + } + else + { + Log::Write( + Logger::Level::Informational, "Unknown port specified, assuming non-TLS connection."); + connectionUrl = "amqp://"; + } + connectionUrl += hostName + ":" + std::to_string(port); + m_hostUrl = Azure::Core::Url(connectionUrl); +#else + throw std::runtime_error("Not implemented"); + +#endif } ConnectionImpl::~ConnectionImpl() @@ -231,14 +324,13 @@ namespace Azure { namespace Core { namespace Amqp { namespace _detail { Azure::Core::_internal::AzureNoReturnPath("Connection is being destroyed while open."); } m_isClosing = true; - +#if ENABLE_UAMQP // If the connection is going away, we don't want to generate any more events on it. if (m_eventHandler) { m_eventHandler = nullptr; } -#if ENABLE_UAMQP m_connection.reset(); #endif lock.unlock(); @@ -253,7 +345,6 @@ namespace Azure { namespace Core { namespace Amqp { namespace _detail { } m_containerId = containerId; #if ENABLE_UAMQP - m_connection.reset(connection_create2( *m_transport, m_hostName.c_str(), @@ -288,9 +379,104 @@ namespace Azure { namespace Core { namespace Amqp { namespace _detail { { throw std::runtime_error("Failed to set connection properties."); } +#elif ENABLE_RUST_AMQP + // Transfer the configuration options to the connection options builder. + UniqueAmqpConnectionOptionsBuilder builder{amqpconnectionoptionsbuilder_create()}; + if (amqpconnectionoptionsbuilder_set_max_frame_size(builder.get(), m_options.MaxFrameSize)) + { + throw std::runtime_error("Failed to set max frame size."); + } + if (amqpconnectionoptionsbuilder_set_channel_max(builder.get(), m_options.MaxChannelCount)) + { + throw std::runtime_error("Failed to set max channel count."); + } + if (amqpconnectionoptionsbuilder_set_idle_timeout( + builder.get(), + static_cast( + std::chrono::duration_cast(m_options.IdleTimeout) + .count()))) + { + throw std::runtime_error("Failed to set idle timeout."); + } + if (!m_options.IncomingLocales.empty()) + { + std::vector locales; + for (auto& locale : m_options.IncomingLocales) + { + locales.push_back(const_cast(locale.c_str())); + } + + if (amqpconnectionoptionsbuilder_set_incoming_locales( + builder.get(), locales.data(), locales.size())) + { + throw std::runtime_error("Failed to set incoming locales."); + } + } + if (!m_options.OutgoingLocales.empty()) + { + std::vector locales; + for (auto& locale : m_options.OutgoingLocales) + { + locales.push_back(const_cast(locale.c_str())); + } + + if (amqpconnectionoptionsbuilder_set_outgoing_locales( + builder.get(), locales.data(), locales.size())) + { + throw std::runtime_error("Failed to set incoming locales."); + } + } + if (!m_options.OfferedCapabilities.empty()) + { + std::vector capabilities; + for (auto& capability : m_options.OfferedCapabilities) + { + capabilities.push_back(const_cast(capability.c_str())); + } + + if (amqpconnectionoptionsbuilder_set_offered_capabilities( + builder.get(), capabilities.data(), capabilities.size())) + { + throw std::runtime_error("Failed to set incoming locales."); + } + } + if (!m_options.DesiredCapabilities.empty()) + { + std::vector capabilities; + for (auto& capability : m_options.DesiredCapabilities) + { + capabilities.push_back(const_cast(capability.c_str())); + } + + if (amqpconnectionoptionsbuilder_set_desired_capabilities( + builder.get(), capabilities.data(), capabilities.size())) + { + throw std::runtime_error("Failed to set incoming locales."); + } + } + + if (!m_options.Properties.empty()) + { + if (amqpconnectionoptionsbuilder_set_properties( + builder.get(), + Models::_detail::AmqpValueFactory::ToImplementation( + m_options.Properties.AsAmqpValue()))) + { + throw std::runtime_error("Failed to set connection properties."); + } + } + + if (amqpconnectionoptionsbuilder_set_buffer_size(builder.get(), m_options.BufferSize)) + { + throw std::runtime_error("Failed to set buffer size."); + } + + m_connectionOptions.reset(amqpconnectionoptionsbuilder_build(builder.get())); + #endif } +#if ENABLE_UAMQP void ConnectionImpl::Poll() { std::unique_lock lock(m_amqpMutex); @@ -309,6 +495,7 @@ namespace Azure { namespace Core { namespace Amqp { namespace _detail { #endif } } +#endif namespace { #if ENABLE_UAMQP @@ -437,7 +624,7 @@ namespace Azure { namespace Core { namespace Amqp { namespace _detail { } } } -#endif + void ConnectionImpl::EnableAsyncOperation(bool enable) { m_enableAsyncOperation = enable; @@ -480,6 +667,7 @@ namespace Azure { namespace Core { namespace Amqp { namespace _detail { } } } +#endif void ConnectionImpl::Open() { @@ -493,11 +681,22 @@ namespace Azure { namespace Core { namespace Amqp { namespace _detail { { throw std::runtime_error("Could not open connection."); } -#endif m_connectionOpened = true; EnableAsyncOperation(true); +#elif ENABLE_RUST_AMQP + if (amqpconnection_open( + Azure::Core::Amqp::Common::_detail::RustThreadContextInstance.GetRuntimeContext(), + m_connection.get(), + m_hostUrl.GetAbsoluteUrl().c_str(), + m_containerId.c_str(), + m_connectionOptions.get())) + { + throw std::runtime_error("Could not open connection."); + } +#endif } +#if ENABLE_UAMQP void ConnectionImpl::Listen() { Log::Stream(Logger::Level::Verbose) @@ -507,11 +706,12 @@ namespace Azure { namespace Core { namespace Amqp { namespace _detail { { throw std::runtime_error("Could not listen on connection."); } -#endif m_connectionOpened = true; EnableAsyncOperation(true); +#endif } +#endif void ConnectionImpl::Close( const std::string& condition, @@ -542,10 +742,30 @@ namespace Azure { namespace Core { namespace Amqp { namespace _detail { throw std::runtime_error("Could not close connection."); } } -#else - (void)condition; - (void)description; - (void)info; +#elif ENABLE_RUST_AMQP + if (!m_connection) + { + throw std::logic_error("Connection not opened."); + } + if (condition.empty() && description.empty() && info.IsNull()) + { + if (amqpconnection_close(runtime_context_new(), m_connection.get())) + { + throw std::runtime_error("Could not close connection."); + } + } + else + { + if (amqpconnection_close_with_error( + Azure::Core::Amqp::Common::_detail::RustThreadContextInstance.GetRuntimeContext(), + m_connection.get(), + condition.c_str(), + description.c_str(), + Models::_detail::AmqpValueFactory::ToImplementation(info))) + { + throw std::runtime_error("Could not close connection."); + } + } #endif m_connectionOpened = false; } @@ -558,6 +778,8 @@ namespace Azure { namespace Core { namespace Amqp { namespace _detail { { throw std::runtime_error("Could not get max frame size."); } +#elif ENABLE_RUST_AMQP + maxSize = amqpconnectionoptions_get_max_frame_size(m_connectionOptions.get()); #endif return maxSize; } @@ -570,6 +792,8 @@ namespace Azure { namespace Core { namespace Amqp { namespace _detail { { throw std::runtime_error("Could not get channel max."); } +#elif ENABLE_RUST_AMQP + maxChannel = amqpconnectionoptions_get_channel_max(m_connectionOptions.get()); #endif return maxChannel; } @@ -583,8 +807,9 @@ namespace Azure { namespace Core { namespace Amqp { namespace _detail { throw std::runtime_error("Could not set max frame size."); } return std::chrono::milliseconds(ms); -#else - return {}; +#elif ENABLE_RUST_AMQP + return std::chrono::milliseconds( + amqpconnectionoptions_get_idle_timeout(m_connectionOptions.get())); #endif } @@ -596,38 +821,36 @@ namespace Azure { namespace Core { namespace Amqp { namespace _detail { { throw std::runtime_error("Could not get properties."); } +#else + auto value = amqpconnectionoptions_get_properties(m_connectionOptions.get()); +#endif return Models::_detail::AmqpValueFactory::FromImplementation( Models::_detail::UniqueAmqpValueHandle{value}) .AsMap(); -#else - return {}; -#endif } +#if ENABLE_UAMQP uint32_t ConnectionImpl::GetRemoteMaxFrameSize() const { uint32_t maxFrameSize = {}; -#if ENABLE_UAMQP if (connection_get_remote_max_frame_size(m_connection.get(), &maxFrameSize)) { throw std::runtime_error("Could not get remote max frame size."); } -#endif return maxFrameSize; } +#endif +#if ENABLE_UAMQP void ConnectionImpl::SetIdleEmptyFrameSendPercentage(double ratio) { std::unique_lock lock(m_amqpMutex); -#if ENABLE_UAMQP if (connection_set_remote_idle_timeout_empty_frame_send_ratio(m_connection.get(), ratio)) { throw std::runtime_error("Could not set remote idle timeout send frame ratio."); } -#else - (void)ratio; -#endif } +#endif bool ConnectionImpl::IsSasCredential() const { @@ -653,7 +876,8 @@ namespace Azure { namespace Core { namespace Amqp { namespace _detail { { Log::Stream(Logger::Level::Verbose) << "Authenticate connection for audience " << audience; } - // If the audience looks like a URL for AMQP, AMQPS, or SB, we can use the URL as provided. + // If the audience looks like a URL for AMQP, AMQPS, or SB, we can use the URL as + // provided. if ((audience.find("amqps://") != 0) && (audience.find("amqp://") != 0) && (audience.find("sb://") != 0)) { diff --git a/sdk/core/azure-core-amqp/src/amqp/connection_string_credential.cpp b/sdk/core/azure-core-amqp/src/amqp/connection_string_credential.cpp index f866d88b21..9d3f9e7e73 100644 --- a/sdk/core/azure-core-amqp/src/amqp/connection_string_credential.cpp +++ b/sdk/core/azure-core-amqp/src/amqp/connection_string_credential.cpp @@ -124,6 +124,7 @@ namespace Azure { namespace Core { namespace Amqp { namespace _internal { } } +#if ENABLE_UAMQP std::shared_ptr ServiceBusSasConnectionStringCredential::GetTransport() const { @@ -132,6 +133,7 @@ namespace Azure { namespace Core { namespace Amqp { namespace _internal { return std::make_shared( Network::_internal::SocketTransportFactory::Create(GetHostName(), GetPort())); } +#endif Credentials::AccessToken ServiceBusSasConnectionStringCredential::GetToken( Credentials::TokenRequestContext const& tokenRequestContext, diff --git a/sdk/core/azure-core-amqp/src/amqp/link.cpp b/sdk/core/azure-core-amqp/src/amqp/link.cpp index dbcd19db87..00ec2ccb51 100644 --- a/sdk/core/azure-core-amqp/src/amqp/link.cpp +++ b/sdk/core/azure-core-amqp/src/amqp/link.cpp @@ -20,6 +20,7 @@ namespace Azure { namespace Core { namespace Amqp { namespace _detail { #if defined(_azure_TESTING_BUILD) +#if ENABLE_UAMQP class LinkImplEventsImpl : public LinkImplEvents { public: LinkImplEventsImpl(LinkEvents* linkEvents) : m_linkEvents(linkEvents) {} @@ -57,25 +58,40 @@ namespace Azure { namespace Core { namespace Amqp { namespace _detail { LinkEvents* m_linkEvents; }; +#endif // ENABLE_UAMQP Link::Link( _internal::Session const& session, std::string const& name, Azure::Core::Amqp::_internal::SessionRole role, Models::_internal::MessageSource const& source, - Models::_internal::MessageTarget const& target, - LinkEvents* linkEvents) - : m_implEvents{std::make_shared(linkEvents)}, - m_impl{std::make_shared( - SessionFactory::GetImpl(session), - name, - role, - source, - target, - m_implEvents.get())} + Models::_internal::MessageTarget const& target +#if ENABLE_UAMQP + , + LinkEvents* linkEvents +#endif + ) + : +#if ENABLE_UAMQP + m_implEvents{std::make_shared(linkEvents)}, +#endif + m_impl + { + std::make_shared( + SessionFactory::GetImpl(session), + name, + role, + source, + target +#if ENABLE_UAMQP + , + m_implEvents.get() +#endif + ) + } { } - +#if ENABLE_UAMQP Link::Link( _internal::Session const& session, _internal::LinkEndpoint& linkEndpoint, @@ -95,6 +111,7 @@ namespace Azure { namespace Core { namespace Amqp { namespace _detail { m_implEvents.get())} { } +#endif Link::~Link() noexcept {} @@ -149,11 +166,12 @@ namespace Azure { namespace Core { namespace Amqp { namespace _detail { std::string Link::GetName() const { return m_impl->GetName(); } uint32_t Link::GetReceivedMessageId() const { return m_impl->GetReceivedMessageId(); } - void Link::Attach() { +#if ENABLE_UAMQP Azure::Core::Amqp::Common::_detail::GlobalStateHolder::GlobalStateInstance()->AddPollable( m_impl); +#endif return m_impl->Attach(); } @@ -171,8 +189,10 @@ namespace Azure { namespace Core { namespace Amqp { namespace _detail { Models::AmqpValue const& info) { m_impl->Detach(close, errorCondition, errorDescription, info); +#if ENABLE_UAMQP Azure::Core::Amqp::Common::_detail::GlobalStateHolder::GlobalStateInstance()->RemovePollable( m_impl); +#endif } #endif // _azure_TESTING_BUILD @@ -233,9 +253,20 @@ namespace Azure { namespace Core { namespace Amqp { namespace _detail { std::string const& name, _internal::SessionRole role, Models::_internal::MessageSource const& source, - Models::_internal::MessageTarget const& target, - LinkImplEvents* events) - : m_session{session}, m_source(source), m_target(target), m_eventHandler{events} + Models::_internal::MessageTarget const& target +#if ENABLE_UAMQP + , + LinkImplEvents* events +#endif + ) + : m_session{session}, m_source(source), m_target(target) +#if ENABLE_UAMQP + , + m_eventHandler + { + events + } +#endif { Models::AmqpValue sourceValue{source.AsAmqpValue()}; Models::AmqpValue targetValue(target.AsAmqpValue()); @@ -256,6 +287,7 @@ namespace Azure { namespace Core { namespace Amqp { namespace _detail { #endif } +#if ENABLE_UAMQP LinkImpl::LinkImpl( std::shared_ptr<_detail::SessionImpl> session, _internal::LinkEndpoint& linkEndpoint, @@ -269,7 +301,6 @@ namespace Azure { namespace Core { namespace Amqp { namespace _detail { Models::AmqpValue sourceValue(source.AsAmqpValue()); Models::AmqpValue targetValue(target.AsAmqpValue()); auto connectionLock{m_session->GetConnection()->Lock()}; -#if ENABLE_UAMQP m_link = link_create_from_endpoint( *session, LinkEndpointFactory::Release(linkEndpoint), @@ -277,13 +308,8 @@ namespace Azure { namespace Core { namespace Amqp { namespace _detail { role == _internal::SessionRole::Sender ? role_sender : role_receiver, Models::_detail::AmqpValueFactory::ToImplementation(sourceValue), Models::_detail::AmqpValueFactory::ToImplementation(targetValue)); -#else - (void)linkEndpoint; - (void)name; - (void)role; - -#endif } +#endif LinkImpl::~LinkImpl() noexcept { @@ -536,28 +562,22 @@ namespace Azure { namespace Core { namespace Amqp { namespace _detail { #endif } +#if ENABLE_UAMQP void LinkImpl::SubscribeToDetachEvent(OnLinkDetachEvent onLinkDetach) { -#if ENABLE_UAMQP m_onLinkDetachEvent = std::move(onLinkDetach); m_linkSubscriptionHandle = link_subscribe_on_link_detach_received(m_link, OnLinkDetachEventFn, this); -#else - (void)onLinkDetach; -#endif } void LinkImpl::UnsubscribeFromDetachEvent() { -#if ENABLE_UAMQP if (m_linkSubscriptionHandle != nullptr) { link_unsubscribe_on_link_detach_received(m_linkSubscriptionHandle); m_linkSubscriptionHandle = nullptr; } -#endif } -#if ENABLE_UAMQP void LinkImpl::OnLinkDetachEventFn(void* context, ERROR_HANDLE error) { LinkImpl* link = static_cast(context); @@ -629,14 +649,14 @@ namespace Azure { namespace Core { namespace Amqp { namespace _detail { } #endif +#if ENABLE_UAMQP void LinkImpl::Poll() { -#if ENABLE_UAMQP // Ensure that the connection hierarchy's state is not modified while polling on the link. auto lock{m_session->GetConnection()->Lock()}; link_dowork(m_link); -#endif } +#endif void LinkImpl::ResetLinkCredit(std::uint32_t linkCredit, bool drain) { @@ -661,9 +681,9 @@ namespace Azure { namespace Core { namespace Amqp { namespace _detail { throw std::runtime_error("Could not set attach properties."); } } -#endif // Mark the connection as async so that we can use the async APIs. m_session->GetConnection()->EnableAsyncOperation(true); +#endif } void LinkImpl::Detach( bool close, @@ -684,13 +704,13 @@ namespace Azure { namespace Core { namespace Amqp { namespace _detail { throw std::runtime_error("Could not set attach properties."); } } + m_session->GetConnection()->EnableAsyncOperation(false); #else (void)close; (void)condition; (void)description; (void)info; #endif - m_session->GetConnection()->EnableAsyncOperation(false); } #if ENABLE_UAMQP @@ -791,5 +811,4 @@ namespace Azure { namespace Core { namespace Amqp { namespace _detail { throw std::runtime_error("Not implemented."); #endif } - }}}} // namespace Azure::Core::Amqp::_detail diff --git a/sdk/core/azure-core-amqp/src/amqp/management.cpp b/sdk/core/azure-core-amqp/src/amqp/management.cpp index 3bde27926e..803261dd76 100644 --- a/sdk/core/azure-core-amqp/src/amqp/management.cpp +++ b/sdk/core/azure-core-amqp/src/amqp/management.cpp @@ -97,7 +97,14 @@ namespace Azure { namespace Core { namespace Amqp { namespace _detail { messageSenderOptions.AuthenticationRequired = false; m_messageSender = std::make_shared( - m_session, m_options.ManagementNodeName, messageSenderOptions, this); + m_session, + m_options.ManagementNodeName, + messageSenderOptions +#if ENABLE_UAMQP + , + this +#endif + ); } { _internal::MessageReceiverOptions messageReceiverOptions; diff --git a/sdk/core/azure-core-amqp/src/amqp/message_receiver.cpp b/sdk/core/azure-core-amqp/src/amqp/message_receiver.cpp index 09c591e91f..2b62033667 100644 --- a/sdk/core/azure-core-amqp/src/amqp/message_receiver.cpp +++ b/sdk/core/azure-core-amqp/src/amqp/message_receiver.cpp @@ -134,6 +134,7 @@ namespace Azure { namespace Core { namespace Amqp { namespace _internal { } #if defined(_azure_TESTING_BUILD) +#if ENABLE_UAMQP void MessageReceiver::EnableLinkPolling() { if (m_impl) @@ -146,6 +147,7 @@ namespace Azure { namespace Core { namespace Amqp { namespace _internal { } } #endif +#endif }}}} // namespace Azure::Core::Amqp::_internal @@ -218,12 +220,7 @@ namespace Azure { namespace Core { namespace Amqp { namespace _detail { void MessageReceiverImpl::CreateLink() { m_link = std::make_shared<_detail::LinkImpl>( - m_session, - m_options.Name, - SessionRole::Receiver, - m_source, - m_options.MessageTarget, - nullptr); + m_session, m_options.Name, SessionRole::Receiver, m_source, m_options.MessageTarget); PopulateLinkProperties(); #if ENABLE_UAMQP @@ -370,7 +367,7 @@ namespace Azure { namespace Core { namespace Amqp { namespace _detail { return {}; } } - +#if ENABLE_UAMQP void MessageReceiverImpl::EnableLinkPolling() { std::unique_lock lock{m_mutableState}; @@ -380,6 +377,7 @@ namespace Azure { namespace Core { namespace Amqp { namespace _detail { m_linkPollingEnabled = true; } } +#endif MessageReceiverImpl::~MessageReceiverImpl() noexcept { @@ -564,11 +562,14 @@ namespace Azure { namespace Core { namespace Amqp { namespace _detail { { Log::Stream(Logger::Level::Verbose) << "Opening message receiver. Start async"; } +#if ENABLE_UAMQP // Mark the connection as async so that we can use the async APIs. m_session->GetConnection()->EnableAsyncOperation(true); +#endif } +#if ENABLE_UAMQP // And add the link to the list of pollable items. // // Note that you *cannot* hold any connection or link locks when calling AddPollable. This is @@ -582,6 +583,7 @@ namespace Azure { namespace Core { namespace Amqp { namespace _detail { { EnableLinkPolling(); } +#endif } void MessageReceiverImpl::Close(Context const& context) @@ -600,12 +602,14 @@ namespace Azure { namespace Core { namespace Amqp { namespace _detail { { std::unique_lock lock{m_mutableState}; +#if ENABLE_UAMQP if (m_linkPollingEnabled) { Common::_detail::GlobalStateHolder::GlobalStateInstance()->RemovePollable( m_link); // This will ensure that the link is cleaned up on the next poll() m_linkPollingEnabled = false; } +#endif } { auto lock{m_session->GetConnection()->Lock()}; @@ -659,7 +663,9 @@ namespace Azure { namespace Core { namespace Amqp { namespace _detail { { Log::Stream(Logger::Level::Verbose) << "Closing message receiver. Stop async"; } +#if ENABLE_UAMQP m_session->GetConnection()->EnableAsyncOperation(false); +#endif m_receiverOpen = false; } diff --git a/sdk/core/azure-core-amqp/src/amqp/message_sender.cpp b/sdk/core/azure-core-amqp/src/amqp/message_sender.cpp index 4b1bea19d3..34d36553d8 100644 --- a/sdk/core/azure-core-amqp/src/amqp/message_sender.cpp +++ b/sdk/core/azure-core-amqp/src/amqp/message_sender.cpp @@ -132,12 +132,20 @@ namespace Azure { namespace Core { namespace Amqp { namespace _detail { MessageSenderImpl::MessageSenderImpl( std::shared_ptr<_detail::SessionImpl> session, Models::_internal::MessageTarget const& target, - _internal::MessageSenderOptions const& options, - _internal::MessageSenderEvents* events) - : m_events{events}, m_session{session}, m_target{target}, m_options{options} + _internal::MessageSenderOptions const& options +#if ENABLE_UAMQP + , + _internal::MessageSenderEvents* events +#endif + ) + : +#if ENABLE_UAMQP + m_events{events}, +#endif + m_session{session}, m_target{target}, m_options{options} { } - +#if ENABLE_UAMQP MessageSenderImpl::MessageSenderImpl( std::shared_ptr<_detail::SessionImpl> session, _internal::LinkEndpoint& endpoint, @@ -147,13 +155,12 @@ namespace Azure { namespace Core { namespace Amqp { namespace _detail { : m_events{events}, m_session{session}, m_target{target}, m_options{options} { CreateLink(endpoint); -#if ENABLE_UAMQP m_messageSender.reset( messagesender_create(*m_link, MessageSenderImpl::OnMessageSenderStateChangedFn, this)); messagesender_set_trace(m_messageSender.get(), m_options.EnableTrace); -#endif } +#endif MessageSenderImpl::~MessageSenderImpl() noexcept { @@ -173,9 +180,11 @@ namespace Azure { namespace Core { namespace Amqp { namespace _detail { if (m_link) { +#if ENABLE_UAMQP // Unsubscribe from any detach events before clearing out the event handler to short-circuit // any events firing after the object is destroyed. m_link->UnsubscribeFromDetachEvent(); +#endif m_link.reset(); } @@ -187,6 +196,7 @@ namespace Azure { namespace Core { namespace Amqp { namespace _detail { #endif } +#if ENABLE_UAMQP void MessageSenderImpl::CreateLink(_internal::LinkEndpoint& endpoint) { m_link = std::make_shared<_detail::LinkImpl>( @@ -198,10 +208,10 @@ namespace Azure { namespace Core { namespace Amqp { namespace _detail { m_target, nullptr); PopulateLinkProperties(); - m_link->SubscribeToDetachEvent( [this](Models::_internal::AmqpError const& error) { OnLinkDetached(error); }); } +#endif void MessageSenderImpl::CreateLink() { @@ -210,12 +220,12 @@ namespace Azure { namespace Core { namespace Amqp { namespace _detail { m_options.Name, _internal::SessionRole::Sender, // This is the role of the link, not the endpoint. m_options.MessageSource, - m_target, - nullptr); + m_target); PopulateLinkProperties(); - +#if ENABLE_UAMQP m_link->SubscribeToDetachEvent( [this](Models::_internal::AmqpError const& error) { OnLinkDetached(error); }); +#endif } /* Populate link properties from options. */ @@ -390,10 +400,11 @@ namespace Azure { namespace Core { namespace Amqp { namespace _detail { { Log::Stream(Logger::Level::Verbose) << "Opening message sender. Enable async operation."; } +#if ENABLE_UAMQP m_session->GetConnection()->EnableAsyncOperation(true); - // Enable async on the link as well. Common::_detail::GlobalStateHolder::GlobalStateInstance()->AddPollable(m_link); +#endif } if (!halfOpen) { @@ -404,16 +415,16 @@ namespace Azure { namespace Core { namespace Amqp { namespace _detail { { Log::Stream(Logger::Level::Verbose) << "Opening message sender. Enable async operation."; } +#if ENABLE_UAMQP m_session->GetConnection()->EnableAsyncOperation(false); - +#endif // Clean up from changes made earlier in the open, since the open was not successful. auto lock{m_session->GetConnection()->Lock()}; - +#if ENABLE_UAMQP m_link->UnsubscribeFromDetachEvent(); Common::_detail::GlobalStateHolder::GlobalStateInstance()->RemovePollable( m_link); // This will ensure that the link is cleaned up on the next poll() -#if ENABLE_UAMQP messagesender_close(m_messageSender.get()); m_link.reset(); m_messageSender.reset(); @@ -445,10 +456,10 @@ namespace Azure { namespace Core { namespace Amqp { namespace _detail { { Log::Stream(Logger::Level::Verbose) << "Closing message sender."; } - +#if ENABLE_UAMQP Common::_detail::GlobalStateHolder::GlobalStateInstance()->RemovePollable( m_link); // This will ensure that the link is cleaned up on the next poll() - +#endif bool shouldWaitForClose = m_currentState == _internal::MessageSenderState::Closing || m_currentState == _internal::MessageSenderState::Open; @@ -506,13 +517,15 @@ namespace Azure { namespace Core { namespace Amqp { namespace _detail { << "Sender Unsubscribe from link detach event. Link instance: " << m_link->GetUnderlyingLink(); } -#endif m_link->UnsubscribeFromDetachEvent(); +#endif // Now that the connection is closed, the link is no longer needed. This will free the link m_link.reset(); } +#if ENABLE_UAMQP m_session->GetConnection()->EnableAsyncOperation(false); +#endif m_senderOpen = false; } diff --git a/sdk/core/azure-core-amqp/src/amqp/private/connection_impl.hpp b/sdk/core/azure-core-amqp/src/amqp/private/connection_impl.hpp index c4cdd973b3..c07b733e45 100644 --- a/sdk/core/azure-core-amqp/src/amqp/private/connection_impl.hpp +++ b/sdk/core/azure-core-amqp/src/amqp/private/connection_impl.hpp @@ -9,8 +9,11 @@ #include "unique_handle.hpp" #include +#include #if ENABLE_UAMQP #include +#elif ENABLE_RUST_AMQP +#include "..\rust_amqp\rust_wrapper\rust_amqp_wrapper.h" #endif #include #include @@ -23,20 +26,55 @@ #endif namespace Azure { namespace Core { namespace Amqp { namespace _detail { + #if ENABLE_UAMQP - template <> struct UniqueHandleHelper + using AmqpConnectionImplementation = CONNECTION_INSTANCE_TAG; +#elif ENABLE_RUST_AMQP + using AmqpConnectionImplementation = RustInterop::RustAmqpConnection; + using AmqpConnectionOptionsImplementation = RustInterop::RustAmqpConnectionOptions; + using AmqpConnectionOptionsBuilderImplementation = RustInterop::RustAmqpConnectionOptionsBuilder; +#endif + + template <> struct UniqueHandleHelper + { + static void FreeAmqpConnection(AmqpConnectionImplementation* obj); + + using type + = Core::_internal::BasicUniqueHandle; + }; + +#if ENABLE_RUST_AMQP + template <> struct UniqueHandleHelper { - static void FreeAmqpConnection(CONNECTION_HANDLE obj); + static void FreeAmqpConnectionOptions(AmqpConnectionOptionsImplementation* obj); - using type = Core::_internal::BasicUniqueHandle; + using type = Core::_internal:: + BasicUniqueHandle; }; + + template <> struct UniqueHandleHelper + { + static void FreeAmqpConnectionOptionsBuilder(AmqpConnectionOptionsBuilderImplementation* obj); + + using type = Core::_internal::BasicUniqueHandle< + AmqpConnectionOptionsBuilderImplementation, + FreeAmqpConnectionOptionsBuilder>; + }; + #endif }}}} // namespace Azure::Core::Amqp::_detail namespace Azure { namespace Core { namespace Amqp { namespace _detail { -#if ENABLE_UAMQP - using UniqueAmqpConnection = UniqueHandle; + using UniqueAmqpConnection + = UniqueHandle; +#if ENABLE_RUST_AMQP + using UniqueAmqpConnectionOptions + = UniqueHandle; + using UniqueAmqpConnectionOptionsBuilder + = UniqueHandle; +#endif +#if ENABLE_UAMQP std::ostream& operator<<(std::ostream& os, CONNECTION_STATE state); #endif class ClaimsBasedSecurity; @@ -56,20 +94,30 @@ namespace Azure { namespace Core { namespace Amqp { namespace _detail { } }; - class ConnectionImpl final : public std::enable_shared_from_this, - public Common::_detail::Pollable { + class ConnectionImpl final : public std::enable_shared_from_this +#if ENABLE_UAMQP + , + public Common::_detail::Pollable +#endif + { public: +#if ENABLE_UAMQP ConnectionImpl( std::shared_ptr transport, _internal::ConnectionOptions const& options, _internal::ConnectionEvents* eventHandler, _internal::ConnectionEndpointEvents* endpointEvents); +#endif ConnectionImpl( std::string const& hostName, std::shared_ptr tokenCredential, - _internal::ConnectionOptions const& options, - _internal::ConnectionEvents* eventHandler); + _internal::ConnectionOptions const& options +#if ENABLE_UAMQP + , + _internal::ConnectionEvents* eventHandler +#endif + ); virtual ~ConnectionImpl(); @@ -95,28 +143,49 @@ namespace Azure { namespace Core { namespace Amqp { namespace _detail { #endif void Open(); +#if ENABLE_UAMQP void Listen(); +#endif void Close( std::string const& condition = {}, std::string const& description = {}, Models::AmqpValue info = {}); +#if ENABLE_UAMQP void Poll() override; - - std::string GetHost() const { return m_hostName; } - uint16_t GetPort() const { return m_port; } +#endif + std::string GetHost() const + { +#if ENABLE_UAMQP + return m_hostName; +#elif ENABLE_RUST_AMQP + return m_hostUrl.GetHost(); +#endif + } + uint16_t GetPort() const + { +#if ENABLE_UAMQP + return m_port; +#elif ENABLE_RUST_AMQP + return m_hostUrl.GetPort(); +#endif + } uint32_t GetMaxFrameSize() const; - uint32_t GetRemoteMaxFrameSize() const; uint16_t GetMaxChannel() const; std::chrono::milliseconds GetIdleTimeout() const; +#if ENABLE_UAMQP + uint32_t GetRemoteMaxFrameSize() const; void SetIdleEmptyFrameSendPercentage(double idleTimeoutEmptyFrameSendRatio); +#endif Models::AmqpMap GetProperties() const; std::shared_ptr GetCredential() const { return m_credential; } +#if ENABLE_UAMQP void EnableAsyncOperation(bool enable); bool IsAsyncOperation() { return m_enableAsyncOperation; } +#endif bool IsTraceEnabled() { return m_options.EnableTrace; } bool IsSasCredential() const; @@ -134,19 +203,26 @@ namespace Azure { namespace Core { namespace Amqp { namespace _detail { } private: - std::shared_ptr m_transport; #if ENABLE_UAMQP - UniqueAmqpConnection m_connection{}; + std::shared_ptr m_transport; #endif + UniqueAmqpConnection m_connection{}; +#if ENABLE_UAMQP std::string m_hostName; uint16_t m_port{}; +#elif ENABLE_RUST_AMQP + Azure::Core::Url m_hostUrl; + UniqueAmqpConnectionOptions m_connectionOptions{}; +#endif std::string m_containerId; _internal::ConnectionOptions m_options; Azure::Core::Amqp::Common::_internal::AsyncOperationQueue> m_newSessionQueue; +#if ENABLE_UAMQP _internal::ConnectionEvents* m_eventHandler{}; _internal::ConnectionEndpointEvents* m_endpointEvents{}; _internal::ConnectionState m_connectionState = _internal::ConnectionState::Start; +#endif LockType m_amqpMutex; bool m_enableAsyncOperation = false; @@ -164,8 +240,8 @@ namespace Azure { namespace Core { namespace Amqp { namespace _detail { _internal::ConnectionEvents* eventHandler, _internal::ConnectionOptions const& options); - void SetState(_internal::ConnectionState newState) { m_connectionState = newState; } #if ENABLE_UAMQP + void SetState(_internal::ConnectionState newState) { m_connectionState = newState; } static void OnConnectionStateChangedFn( void* context, CONNECTION_STATE newState, diff --git a/sdk/core/azure-core-amqp/src/amqp/private/link_impl.hpp b/sdk/core/azure-core-amqp/src/amqp/private/link_impl.hpp index 84310efb4b..0b7d8b0322 100644 --- a/sdk/core/azure-core-amqp/src/amqp/private/link_impl.hpp +++ b/sdk/core/azure-core-amqp/src/amqp/private/link_impl.hpp @@ -20,7 +20,7 @@ #include namespace Azure { namespace Core { namespace Amqp { namespace _detail { - +#if ENABLE_UAMQP class LinkImplEvents { public: virtual Models::AmqpValue OnTransferReceived( @@ -37,20 +37,30 @@ namespace Azure { namespace Core { namespace Amqp { namespace _detail { virtual void OnLinkFlowOn(std::shared_ptr const& link) = 0; virtual ~LinkImplEvents() = default; }; +#endif - class LinkImpl final : public std::enable_shared_from_this, - public Common::_detail::Pollable { - + class LinkImpl final : public std::enable_shared_from_this +#if ENABLE_UAMQP + , + public Common::_detail::Pollable +#endif + { +#if ENABLE_UAMQP using OnLinkDetachEvent = std::function; - +#endif public: LinkImpl( std::shared_ptr<_detail::SessionImpl> session, std::string const& name, _internal::SessionRole role, Models::_internal::MessageSource const& source, - Models::_internal::MessageTarget const& target, - _detail::LinkImplEvents* events); + Models::_internal::MessageTarget const& target +#if ENABLE_UAMQP + , + _detail::LinkImplEvents* events = nullptr +#endif + ); +#if ENABLE_UAMQP LinkImpl( std::shared_ptr<_detail::SessionImpl> session, _internal::LinkEndpoint& linkEndpoint, @@ -59,6 +69,7 @@ namespace Azure { namespace Core { namespace Amqp { namespace _detail { Models::_internal::MessageSource const& source, Models::_internal::MessageTarget const& target, _detail::LinkImplEvents* events); +#endif ~LinkImpl() noexcept; LinkImpl(LinkImpl const&) = delete; @@ -89,11 +100,11 @@ namespace Azure { namespace Core { namespace Amqp { namespace _detail { void SetDesiredCapabilities(Models::AmqpValue desiredCapabilities); Models::AmqpValue GetDesiredCapabilities() const; - +#if ENABLE_UAMQP /** @brief Subscribe to link detach events. */ void SubscribeToDetachEvent(OnLinkDetachEvent onLinkDetachEvent); void UnsubscribeFromDetachEvent(); - +#endif std::string GetName() const; #if ENABLE_UAMQP @@ -130,9 +141,9 @@ namespace Azure { namespace Core { namespace Amqp { namespace _detail { Models::_internal::MessageTarget m_target; Common::_internal::AsyncOperationQueue m_transferCompleteQueue; +#if ENABLE_UAMQP OnLinkDetachEvent m_onLinkDetachEvent; LinkImplEvents* m_eventHandler; -#if ENABLE_UAMQP ON_LINK_DETACH_EVENT_SUBSCRIPTION_HANDLE m_linkSubscriptionHandle{}; static void OnLinkDetachEventFn(void* context, ERROR_HANDLE error); @@ -143,8 +154,8 @@ namespace Azure { namespace Core { namespace Amqp { namespace _detail { TRANSFER_HANDLE transfer, uint32_t payload_size, const unsigned char* payload_bytes); -#endif // Inherited via Pollable void Poll() override; +#endif }; }}}} // namespace Azure::Core::Amqp::_detail diff --git a/sdk/core/azure-core-amqp/src/amqp/private/message_receiver_impl.hpp b/sdk/core/azure-core-amqp/src/amqp/private/message_receiver_impl.hpp index 184ccfa268..ace0819ac1 100644 --- a/sdk/core/azure-core-amqp/src/amqp/private/message_receiver_impl.hpp +++ b/sdk/core/azure-core-amqp/src/amqp/private/message_receiver_impl.hpp @@ -73,9 +73,9 @@ namespace Azure { namespace Core { namespace Amqp { namespace _detail { std::pair, Models::_internal::AmqpError> TryWaitForIncomingMessage(); - +#if ENABLE_UAMQP void EnableLinkPolling(); - +#endif private: #if ENABLE_UAMQP UniqueMessageReceiver m_messageReceiver{}; diff --git a/sdk/core/azure-core-amqp/src/amqp/private/message_sender_impl.hpp b/sdk/core/azure-core-amqp/src/amqp/private/message_sender_impl.hpp index 54aeaa67f3..7118bd54e9 100644 --- a/sdk/core/azure-core-amqp/src/amqp/private/message_sender_impl.hpp +++ b/sdk/core/azure-core-amqp/src/amqp/private/message_sender_impl.hpp @@ -41,14 +41,20 @@ namespace Azure { namespace Core { namespace Amqp { namespace _detail { MessageSenderImpl( std::shared_ptr<_detail::SessionImpl> session, Models::_internal::MessageTarget const& target, - _internal::MessageSenderOptions const& options, - _internal::MessageSenderEvents* events); + _internal::MessageSenderOptions const& options +#if ENABLE_UAMQP + , + _internal::MessageSenderEvents* events = nullptr +#endif + ); +#if ENABLE_UAMQP MessageSenderImpl( std::shared_ptr<_detail::SessionImpl> session, _internal::LinkEndpoint& endpoint, Models::_internal::MessageTarget const& target, _internal::MessageSenderOptions const& options, _internal::MessageSenderEvents* events); +#endif virtual ~MessageSenderImpl() noexcept; MessageSenderImpl(MessageSenderImpl const&) = delete; diff --git a/sdk/core/azure-core-amqp/src/amqp/private/session_impl.hpp b/sdk/core/azure-core-amqp/src/amqp/private/session_impl.hpp index 3c555ee28d..649c2d8a3c 100644 --- a/sdk/core/azure-core-amqp/src/amqp/private/session_impl.hpp +++ b/sdk/core/azure-core-amqp/src/amqp/private/session_impl.hpp @@ -48,16 +48,21 @@ namespace Azure { namespace Core { namespace Amqp { namespace _detail { class SessionImpl final : public std::enable_shared_from_this { public: +#if ENABLE_UAMQP SessionImpl( std::shared_ptr<_detail::ConnectionImpl> parentConnection, _internal::Endpoint& newEndpoint, _internal::SessionOptions const& options, _internal::SessionEvents* eventHandler); - +#endif SessionImpl( std::shared_ptr<_detail::ConnectionImpl> parentConnection, - _internal::SessionOptions const& options, - _internal::SessionEvents* eventHandler); + _internal::SessionOptions const& options +#if ENABLE_UAMQP + , + _internal::SessionEvents* eventHandler = nullptr +#endif + ); ~SessionImpl() noexcept; SessionImpl(SessionImpl const&) = delete; @@ -84,14 +89,18 @@ namespace Azure { namespace Core { namespace Amqp { namespace _detail { private: SessionImpl(); +#if ENABLE_UAMQP bool m_connectionAsyncStarted{false}; +#endif bool m_isBegun{false}; std::shared_ptr<_detail::ConnectionImpl> m_connectionToPoll; #if ENABLE_UAMQP UniqueAmqpSession m_session; #endif _internal::SessionOptions m_options; +#if ENABLE_UAMQP _internal::SessionEvents* m_eventHandler{}; +#endif #if ENABLE_UAMQP static bool OnLinkAttachedFn( diff --git a/sdk/core/azure-core-amqp/src/amqp/session.cpp b/sdk/core/azure-core-amqp/src/amqp/session.cpp index ad81a24cd7..59c526a862 100644 --- a/sdk/core/azure-core-amqp/src/amqp/session.cpp +++ b/sdk/core/azure-core-amqp/src/amqp/session.cpp @@ -64,14 +64,26 @@ namespace Azure { namespace Core { namespace Amqp { namespace _internal { m_impl->SendDetach(linkEndpoint, closeLink, error); } +#if ENABLE_UAMQP MessageSender Session::CreateMessageSender( Models::_internal::MessageTarget const& target, MessageSenderOptions const& options, MessageSenderEvents* events) const +#elif ENABLE_RUST_AMQP + MessageSender Session::CreateMessageSender( + Models::_internal::MessageTarget const& target, + MessageSenderOptions const& options) const +#endif { +#if ENABLE_UAMQP return _detail::MessageSenderFactory::CreateFromInternal( std::make_shared<_detail::MessageSenderImpl>(m_impl, target, options, events)); +#elif ENABLE_RUST_AMQP + return _detail::MessageSenderFactory::CreateFromInternal( + std::make_shared<_detail::MessageSenderImpl>(m_impl, target, options)); +#endif } +#if ENABLE_UAMQP MessageSender Session::CreateMessageSender( LinkEndpoint& endpoint, Models::_internal::MessageTarget const& target, @@ -81,6 +93,7 @@ namespace Azure { namespace Core { namespace Amqp { namespace _internal { return _detail::MessageSenderFactory::CreateFromInternal( std::make_shared<_detail::MessageSenderImpl>(m_impl, endpoint, target, options, events)); } +#endif MessageReceiver Session::CreateMessageReceiver( Models::_internal::MessageSource const& receiverSource, @@ -124,73 +137,72 @@ namespace Azure { namespace Core { namespace Amqp { namespace _detail { // If we have a mismatched begin/end pair, we need to stop polling on the connection so it // gets cleaned up properly. +#if ENABLE_UAMQP if (m_connectionAsyncStarted) { m_connectionToPoll->EnableAsyncOperation(false); } -#if ENABLE_UAMQP auto lock{m_connectionToPoll->Lock()}; m_session.reset(); #endif } +#if ENABLE_UAMQP SessionImpl::SessionImpl( std::shared_ptr<_detail::ConnectionImpl> connection, _internal::Endpoint& endpoint, _internal::SessionOptions const& options, _internal::SessionEvents* eventHandler) - : m_connectionToPoll(connection), -#if ENABLE_UAMQP - m_session{session_create_from_endpoint( - *connection, - EndpointFactory::Release(endpoint), - SessionImpl::OnLinkAttachedFn, - this)}, -#endif + : m_connectionToPoll(connection), m_session{session_create_from_endpoint( + *connection, + EndpointFactory::Release(endpoint), + SessionImpl::OnLinkAttachedFn, + this)}, m_options{options}, m_eventHandler{eventHandler} { if (options.MaximumLinkCount.HasValue()) { -#if ENABLE_UAMQP if (session_set_handle_max(m_session.get(), options.MaximumLinkCount.Value())) { throw std::runtime_error("Could not set handle max."); } -#endif } if (options.InitialIncomingWindowSize.HasValue()) { -#if ENABLE_UAMQP if (session_set_incoming_window(m_session.get(), options.InitialIncomingWindowSize.Value())) { throw std::runtime_error("Could not set incoming window"); } -#endif } if (options.InitialOutgoingWindowSize.HasValue()) { -#if ENABLE_UAMQP if (session_set_outgoing_window(m_session.get(), options.InitialOutgoingWindowSize.Value())) { throw std::runtime_error("Could not set outgoing window"); } -#endif } -#if ENABLE_UAMQP -#else - (void)endpoint; -#endif } +#endif SessionImpl::SessionImpl( std::shared_ptr<_detail::ConnectionImpl> connection, - _internal::SessionOptions const& options, - _internal::SessionEvents* eventHandler) + _internal::SessionOptions const& options +#if ENABLE_UAMQP + , + _internal::SessionEvents* eventHandler +#endif + ) : m_connectionToPoll(connection), #if ENABLE_UAMQP m_session{session_create(*connection, SessionImpl::OnLinkAttachedFn, this)}, #endif - m_options{options}, m_eventHandler{eventHandler} + m_options + { + options + } +#if ENABLE_UAMQP + , m_eventHandler { eventHandler } +#endif { #if ENABLE_UAMQP @@ -276,102 +288,105 @@ namespace Azure { namespace Core { namespace Amqp { namespace _detail { m_isBegun = true; - // Mark the connection as async so that we can use the async APIs. - GetConnection()->EnableAsyncOperation(true); - m_connectionAsyncStarted = true; - } - void SessionImpl::End(const std::string& condition, const std::string& description) - { - if (!m_isBegun) - { - throw std::runtime_error("Session End without corresponding Begin."); - } +// Mark the connection as async so that we can use the async APIs. #if ENABLE_UAMQP - // When we end the session, it clears all the links, so we need to ensure that the - // m_newLinkAttachedQueue.Clear(); - if (session_end( - m_session.get(), - condition.empty() ? nullptr : condition.c_str(), - description.empty() ? nullptr : description.c_str())) - { - throw std::runtime_error("Could not begin session"); - } + GetConnection()->EnableAsyncOperation(true); + m_connectionAsyncStarted = true; +#endif + } + void SessionImpl::End(const std::string& condition, const std::string& description) + { + if (!m_isBegun) + { + throw std::runtime_error("Session End without corresponding Begin."); + } +#if ENABLE_UAMQP + // When we end the session, it clears all the links, so we need to ensure that the + // m_newLinkAttachedQueue.Clear(); + if (session_end( + m_session.get(), + condition.empty() ? nullptr : condition.c_str(), + description.empty() ? nullptr : description.c_str())) + { + throw std::runtime_error("Could not begin session"); + } + // Mark the connection as async so that we can use the async APIs. + GetConnection()->EnableAsyncOperation(false); + m_connectionAsyncStarted = false; + m_isBegun = false; #else - (void)condition; - (void)description; + (void)condition; + (void)description; #endif - // Mark the connection as async so that we can use the async APIs. - GetConnection()->EnableAsyncOperation(false); - m_connectionAsyncStarted = false; - m_isBegun = false; - } + } - void SessionImpl::SendDetach( - _internal::LinkEndpoint const& linkEndpoint, - bool closeLink, - Models::_internal::AmqpError const& error) const - { - Models::_internal::Performatives::AmqpDetach detach; + void SessionImpl::SendDetach( + _internal::LinkEndpoint const& linkEndpoint, + bool closeLink, + Models::_internal::AmqpError const& error) const + { + Models::_internal::Performatives::AmqpDetach detach; - detach.Closed = closeLink; - detach.Error = error; + detach.Closed = closeLink; + detach.Error = error; #if ENABLE_UAMQP - if (session_send_detach( - linkEndpoint.Get(), Models::_detail::AmqpDetachFactory::ToAmqpDetach(detach).get())) - { - throw std::runtime_error("Failed to send detach performative."); - } + if (session_send_detach( + linkEndpoint.Get(), Models::_detail::AmqpDetachFactory::ToAmqpDetach(detach).get())) + { + throw std::runtime_error("Failed to send detach performative."); + } #else - (void)linkEndpoint; + (void)linkEndpoint; #endif - } + } #if ENABLE_UAMQP - bool SessionImpl::OnLinkAttachedFn( - void* context, - LINK_ENDPOINT_INSTANCE_TAG* newLinkEndpoint, - const char* name, - bool role, - AMQP_VALUE_DATA_TAG* source, - AMQP_VALUE_DATA_TAG* target, - AMQP_VALUE_DATA_TAG* properties) - { - SessionImpl* session = static_cast(context); - _internal::LinkEndpoint linkEndpoint(LinkEndpointFactory::CreateLinkEndpoint(newLinkEndpoint)); - if (session->m_eventHandler) - { - // The input source, target, and properties are owned by the caller, so we need to clone - // them before putting them in a UniqueAmqpValueHandle so we can construct an AmqpValue. - return session->m_eventHandler->OnLinkAttached( - _detail::SessionFactory::CreateFromInternal(session->shared_from_this()), - linkEndpoint, - name, - role == role_receiver ? Azure::Core::Amqp::_internal::SessionRole::Receiver - : Azure::Core::Amqp::_internal::SessionRole::Sender, - Models::_detail::AmqpValueFactory::FromImplementation( - Models::_detail::UniqueAmqpValueHandle{amqpvalue_clone(source)}), - Models::_detail::AmqpValueFactory::FromImplementation( - Models::_detail::UniqueAmqpValueHandle{amqpvalue_clone(target)}), - Models::_detail::AmqpValueFactory::FromImplementation( - Models::_detail::UniqueAmqpValueHandle{amqpvalue_clone(properties)})); - } - else - { - // Even if we don't have any actions to take, if we return false, the connection will be - // aborted. - return true; - } - static_cast(role); - } + bool SessionImpl::OnLinkAttachedFn( + void* context, + LINK_ENDPOINT_INSTANCE_TAG* newLinkEndpoint, + const char* name, + bool role, + AMQP_VALUE_DATA_TAG* source, + AMQP_VALUE_DATA_TAG* target, + AMQP_VALUE_DATA_TAG* properties) + { + SessionImpl* session = static_cast(context); + _internal::LinkEndpoint linkEndpoint( + LinkEndpointFactory::CreateLinkEndpoint(newLinkEndpoint)); + if (session->m_eventHandler) + { + // The input source, target, and properties are owned by the caller, so we need to clone + // them before putting them in a UniqueAmqpValueHandle so we can construct an AmqpValue. + return session->m_eventHandler->OnLinkAttached( + _detail::SessionFactory::CreateFromInternal(session->shared_from_this()), + linkEndpoint, + name, + role == role_receiver ? Azure::Core::Amqp::_internal::SessionRole::Receiver + : Azure::Core::Amqp::_internal::SessionRole::Sender, + Models::_detail::AmqpValueFactory::FromImplementation( + Models::_detail::UniqueAmqpValueHandle{amqpvalue_clone(source)}), + Models::_detail::AmqpValueFactory::FromImplementation( + Models::_detail::UniqueAmqpValueHandle{amqpvalue_clone(target)}), + Models::_detail::AmqpValueFactory::FromImplementation( + Models::_detail::UniqueAmqpValueHandle{amqpvalue_clone(properties)})); + } + else + { + // Even if we don't have any actions to take, if we return false, the connection will be + // aborted. + return true; + } + static_cast(role); + } - _internal::Endpoint EndpointFactory::CreateEndpoint(ENDPOINT_HANDLE endpoint) - { - return _internal::Endpoint(endpoint); - } - _internal::LinkEndpoint LinkEndpointFactory::CreateLinkEndpoint(LINK_ENDPOINT_HANDLE endpoint) - { - return _internal::LinkEndpoint(endpoint); - } + _internal::Endpoint EndpointFactory::CreateEndpoint(ENDPOINT_HANDLE endpoint) + { + return _internal::Endpoint(endpoint); + } + _internal::LinkEndpoint LinkEndpointFactory::CreateLinkEndpoint(LINK_ENDPOINT_HANDLE endpoint) + { + return _internal::LinkEndpoint(endpoint); + } #endif }}}} // namespace Azure::Core::Amqp::_detail diff --git a/sdk/core/azure-core-amqp/src/common/global_state.cpp b/sdk/core/azure-core-amqp/src/common/global_state.cpp index 18c6d977d0..182bffb6db 100644 --- a/sdk/core/azure-core-amqp/src/common/global_state.cpp +++ b/sdk/core/azure-core-amqp/src/common/global_state.cpp @@ -7,6 +7,7 @@ #include #include +#include #if ENABLE_UAMQP #include @@ -104,7 +105,6 @@ namespace Azure { namespace Core { namespace Amqp { namespace Common { namespace // Integrate AMQP logging with Azure Core logging. xlogging_set_log_function(AmqpLogFunction); -#endif m_pollingThread = std::thread([this]() { do @@ -132,16 +132,17 @@ namespace Azure { namespace Core { namespace Amqp { namespace Common { namespace std::this_thread::sleep_for(std::chrono::milliseconds(100)); } while (!m_stopped); }); +#endif } GlobalStateHolder::~GlobalStateHolder() { +#if ENABLE_UAMQP m_stopped = true; if (m_pollingThread.joinable()) { m_pollingThread.join(); } -#if ENABLE_UAMQP platform_deinit(); #if defined(GB_DEBUG_ALLOC) gballoc_deinit(); @@ -149,6 +150,7 @@ namespace Azure { namespace Core { namespace Amqp { namespace Common { namespace #endif } +#if ENABLE_UAMQP /** * @brief Adds a pollable object to the list of objects to be polled. * @@ -199,6 +201,7 @@ namespace Azure { namespace Core { namespace Amqp { namespace Common { namespace while (m_activelyPolling.load()) ; } +#endif GlobalStateHolder* GlobalStateHolder::GlobalStateInstance() { @@ -206,4 +209,18 @@ namespace Azure { namespace Core { namespace Amqp { namespace Common { namespace return &globalState; } +#if ENABLE_RUST_AMQP + thread_local RustThreadContext RustThreadContextInstance; +#endif + }}}}} // namespace Azure::Core::Amqp::Common::_detail + +#if ENABLE_RUST_AMQP +namespace Azure { namespace Core { namespace Amqp { namespace _detail { + void UniqueHandleHelper::FreeRuntimeContext( + RustRuntimeContext* obj) + { + Azure::Core::Amqp::_detail::RustInterop::runtime_context_delete(obj); + } +}}}} // namespace Azure::Core::Amqp::_detail +#endif diff --git a/sdk/core/azure-core-amqp/src/models/private/header_impl.hpp b/sdk/core/azure-core-amqp/src/models/private/header_impl.hpp index 2679b6a530..951a2a3097 100644 --- a/sdk/core/azure-core-amqp/src/models/private/header_impl.hpp +++ b/sdk/core/azure-core-amqp/src/models/private/header_impl.hpp @@ -28,6 +28,7 @@ namespace Azure { namespace Core { namespace Amqp { namespace _detail { #elif ENABLE_RUST_AMQP using HeaderImplementation = Azure::Core::Amqp::_detail::RustInterop::RustMessageHeader; #endif + template <> struct UniqueHandleHelper { static void FreeAmqpHeader(HeaderImplementation* obj); diff --git a/sdk/core/azure-core-amqp/src/network/amqp_header_transport.cpp b/sdk/core/azure-core-amqp/src/network/amqp_header_transport.cpp index 673241ed73..3847438a51 100644 --- a/sdk/core/azure-core-amqp/src/network/amqp_header_transport.cpp +++ b/sdk/core/azure-core-amqp/src/network/amqp_header_transport.cpp @@ -1,15 +1,14 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +#if ENABLE_UAMQP #include "azure/core/amqp/internal/network/amqp_header_detect_transport.hpp" #include "private/transport_impl.hpp" -#if ENABLE_UAMQP #include #include #include #include -#endif #include #include @@ -41,3 +40,4 @@ namespace Azure { namespace Core { namespace Amqp { namespace Network { namespac } }}}}} // namespace Azure::Core::Amqp::Network::_internal +#endif diff --git a/sdk/core/azure-core-amqp/src/network/private/transport_impl.hpp b/sdk/core/azure-core-amqp/src/network/private/transport_impl.hpp index 74a0eca9d1..66ec241aba 100644 --- a/sdk/core/azure-core-amqp/src/network/private/transport_impl.hpp +++ b/sdk/core/azure-core-amqp/src/network/private/transport_impl.hpp @@ -2,27 +2,25 @@ // Licensed under the MIT License. #pragma once +#if ENABLE_UAMQP #include "../../amqp/private/unique_handle.hpp" #include "azure/core/amqp/internal/common/async_operation_queue.hpp" -#if ENABLE_UAMQP #include -#endif + #include #include #include #include namespace Azure { namespace Core { namespace Amqp { namespace _detail { -#if ENABLE_UAMQP template <> struct UniqueHandleHelper { static void FreeXio(XIO_HANDLE obj); using type = Core::_internal::BasicUniqueHandle; }; -#endif // ENABLE_UAMQP }}}} // namespace Azure::Core::Amqp::_detail namespace Azure { namespace Core { namespace Amqp { namespace Network { namespace _detail { @@ -34,11 +32,9 @@ namespace Azure { namespace Core { namespace Amqp { namespace Network { namespac struct TransportImpl : public std::enable_shared_from_this { public: -#if ENABLE_UAMQP TransportImpl( XIO_HANDLE instance, Azure::Core::Amqp::Network::_internal::TransportEvents* eventHandler); -#endif TransportImpl(TransportImpl&& instance) = delete; TransportImpl(Azure::Core::Amqp::Network::_internal::TransportEvents* eventHandler); @@ -48,16 +44,13 @@ namespace Azure { namespace Core { namespace Amqp { namespace Network { namespac virtual bool Send(uint8_t*, size_t, Network::_internal::Transport::TransportSendCompleteFn) const; void Poll() const; -#if ENABLE_UAMQP operator XIO_HANDLE() { return m_xioInstance.get(); } XIO_HANDLE Release() { return m_xioInstance.release(); } -#endif void SetEventHandler(Network::_internal::TransportEvents* eventHandler) { m_eventHandler = eventHandler; } -#if ENABLE_UAMQP static std::shared_ptr CreateFromXioHandle( XIO_HANDLE instance, Network::_internal::TransportEvents* eventHandler) @@ -65,23 +58,19 @@ namespace Azure { namespace Core { namespace Amqp { namespace Network { namespac return std::shared_ptr( new TransportImpl(instance, eventHandler), [](TransportImpl* p) { delete p; }); } -#endif private: -#if ENABLE_UAMQP UniqueXioHandle m_xioInstance{}; -#endif Azure::Core::Amqp::Common::_internal::AsyncOperationQueue<_internal::TransportOpenStatus> m_openCompleteQueue; Azure::Core::Amqp::Common::_internal::AsyncOperationQueue m_closeCompleteQueue; Network::_internal::TransportEvents* m_eventHandler; bool m_isOpen{false}; -#if ENABLE_UAMQP static void OnOpenCompleteFn(void* context, IO_OPEN_RESULT_TAG openResult); static void OnCloseCompleteFn(void* context); static void OnBytesReceivedFn(void* context, const unsigned char* buffer, size_t size); static void OnIOErrorFn(void* context); -#endif // ENABLE_UAMQP }; }}}}} // namespace Azure::Core::Amqp::Network::_detail +#endif // ENABLE_UAMQP diff --git a/sdk/core/azure-core-amqp/src/network/socket_listener.cpp b/sdk/core/azure-core-amqp/src/network/socket_listener.cpp index 85371a8f5b..6b4a45db02 100644 --- a/sdk/core/azure-core-amqp/src/network/socket_listener.cpp +++ b/sdk/core/azure-core-amqp/src/network/socket_listener.cpp @@ -1,17 +1,16 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +#if ENABLE_UAMQP #include "azure/core/amqp/internal/network/socket_listener.hpp" #include "azure/core/amqp/internal/common/global_state.hpp" #include "private/transport_impl.hpp" -#if ENABLE_UAMQP #include #include #include #include -#endif #include #include @@ -30,32 +29,20 @@ namespace Azure { namespace Core { namespace Amqp { namespace Network { namespac } } // namespace - SocketListener::SocketListener(uint16_t port, SocketListenerEvents* eventHandler) : m_eventHandler - { - eventHandler - } -#if ENABLE_UAMQP - , m_socket { socketlistener_create(port) } -#endif + SocketListener::SocketListener(uint16_t port, SocketListenerEvents* eventHandler) + : m_eventHandler{eventHandler}, m_socket{socketlistener_create(port)} { EnsureGlobalStateInitialized(); -#if ENABLE_UAMQP -#else - (void)port; -#endif } SocketListener::~SocketListener() { -#if ENABLE_UAMQP if (m_socket) { socketlistener_destroy(m_socket); m_socket = nullptr; } -#endif } -#if ENABLE_UAMQP void SocketListener::OnSocketAcceptedFn( void* context, const IO_INTERFACE_DESCRIPTION* interfaceDescription, @@ -70,14 +57,12 @@ namespace Azure { namespace Core { namespace Amqp { namespace Network { namespac listener->m_eventHandler->OnSocketAccepted(transport); } } -#endif void SocketListener::Start() { if (m_started) { throw std::runtime_error("Already started."); } -#if ENABLE_UAMQP if (socketlistener_start(m_socket, SocketListener::OnSocketAcceptedFn, this)) { @@ -96,16 +81,12 @@ namespace Azure { namespace Core { namespace Amqp { namespace Network { namespac #endif } m_started = true; -#else - throw std::runtime_error("Not Implemented"); -#endif } void SocketListener::Stop() { if (m_started) { -#if ENABLE_UAMQP if (socketlistener_stop(m_socket)) { auto err = errno; @@ -122,7 +103,6 @@ namespace Azure { namespace Core { namespace Amqp { namespace Network { namespac #pragma warning(pop) #endif } -#endif } else { @@ -131,11 +111,7 @@ namespace Azure { namespace Core { namespace Amqp { namespace Network { namespac m_started = false; } - void SocketListener::Poll() const - { -#if ENABLE_UAMQP - socketlistener_dowork(m_socket); -#endif - } + void SocketListener::Poll() const { socketlistener_dowork(m_socket); } }}}}} // namespace Azure::Core::Amqp::Network::_detail +#endif // ENABLE_UAMQP diff --git a/sdk/core/azure-core-amqp/src/network/socket_transport.cpp b/sdk/core/azure-core-amqp/src/network/socket_transport.cpp index 3dc970515c..5b2686778e 100644 --- a/sdk/core/azure-core-amqp/src/network/socket_transport.cpp +++ b/sdk/core/azure-core-amqp/src/network/socket_transport.cpp @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +#if ENABLE_UAMQP #include "azure/core/amqp/internal/network/socket_transport.hpp" #include "private/transport_impl.hpp" @@ -8,10 +9,8 @@ #include #include -#if ENABLE_UAMQP #include #include -#endif #include #include @@ -28,15 +27,11 @@ namespace Azure { namespace Core { namespace Amqp { namespace Network { namespac { Log::Stream(Logger::Level::Verbose) << "Create socket transport for host " << host << " port: " << port; -#if ENABLE_UAMQP SOCKETIO_CONFIG socketConfig{host.c_str(), port, nullptr}; return _detail::TransportImpl::CreateFromXioHandle( xio_create(socketio_get_interface_description(), &socketConfig), eventHandler); -#else - (void)eventHandler; - throw std::runtime_error("Not implemented."); -#endif // ENABLE_UAMQP } }}}}} // namespace Azure::Core::Amqp::Network::_internal +#endif // ENABLE_UAMQP diff --git a/sdk/core/azure-core-amqp/src/network/tls_transport.cpp b/sdk/core/azure-core-amqp/src/network/tls_transport.cpp index 1c20da2aab..8f345ece7a 100644 --- a/sdk/core/azure-core-amqp/src/network/tls_transport.cpp +++ b/sdk/core/azure-core-amqp/src/network/tls_transport.cpp @@ -8,7 +8,6 @@ #if ENABLE_UAMQP #include #include -#endif #include @@ -19,7 +18,6 @@ namespace Azure { namespace Core { namespace Amqp { namespace Network { namespac uint16_t port, TransportEvents* eventHandler) { -#if ENABLE_UAMQP TLSIO_CONFIG tlsConfig{}; tlsConfig.hostname = host.c_str(); tlsConfig.port = port; @@ -28,13 +26,7 @@ namespace Azure { namespace Core { namespace Amqp { namespace Network { namespac return _detail::TransportImpl::CreateFromXioHandle( xio_create(tlsio_interface, &tlsConfig), eventHandler); -#else - (void)host; - (void)port; - (void)eventHandler; - throw std::runtime_error("Not implemented."); - -#endif // ENABLE_UAMQP } }}}}} // namespace Azure::Core::Amqp::Network::_internal +#endif diff --git a/sdk/core/azure-core-amqp/src/network/transport.cpp b/sdk/core/azure-core-amqp/src/network/transport.cpp index b54fc73169..7958632c16 100644 --- a/sdk/core/azure-core-amqp/src/network/transport.cpp +++ b/sdk/core/azure-core-amqp/src/network/transport.cpp @@ -1,5 +1,6 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +#if ENABLE_UAMQP #include "azure/core/amqp/internal/network/transport.hpp" @@ -7,18 +8,14 @@ #include "azure/core/amqp/internal/common/global_state.hpp" #include "private/transport_impl.hpp" -#if ENABLE_UAMQP #include #include -#endif // ENABLE_UAMQP #include -#if ENABLE_UAMQP namespace Azure { namespace Core { namespace Amqp { namespace _detail { void UniqueHandleHelper::FreeXio(XIO_HANDLE value) { xio_destroy(value); } }}}} // namespace Azure::Core::Amqp::_detail -#endif // ENABLE_UAMQP namespace { void EnsureGlobalStateInitialized() @@ -52,205 +49,176 @@ namespace Azure { namespace Core { namespace Amqp { namespace Network { namespac namespace Azure { namespace Core { namespace Amqp { namespace Network { namespace _detail { TransportImpl::TransportImpl(Network::_internal::TransportEvents* eventHandler) - : -#if ENABLE_UAMQP - m_xioInstance(nullptr), -#endif - m_eventHandler{eventHandler} + : m_xioInstance(nullptr), m_eventHandler{eventHandler} { EnsureGlobalStateInitialized(); } -// This constructor is used by the SocketTransport and TlsTransport classes to construct a -// transport around an already constructed XIO transport. -#if ENABLE_UAMQP - TransportImpl::TransportImpl( - XIO_HANDLE handle, - Network::_internal::TransportEvents* eventHandler) - : m_xioInstance{handle}, m_eventHandler{eventHandler} - { - assert(handle != nullptr); - EnsureGlobalStateInitialized(); - } -#endif - - TransportImpl::~TransportImpl() {} - - template struct CloseCallbackWrapper - { - static void OnOperation(CompleteFn onComplete) { onComplete(); } - }; - -#if ENABLE_UAMQP - void TransportImpl::OnCloseCompleteFn(void* context) - { - TransportImpl* transport = reinterpret_cast(context); - transport->m_closeCompleteQueue.CompleteOperation(true); - } -#endif - void TransportImpl::Close(Context const& context) - { - if (!m_isOpen) - { - throw std::logic_error("Cannot close an unopened transport."); - } -#if ENABLE_UAMQP - if (m_xioInstance) - { - if (xio_close(m_xioInstance.get(), OnCloseCompleteFn, this)) - { - throw std::runtime_error("Failed to close the transport."); - } - m_xioInstance = nullptr; - } -#endif - auto result = m_closeCompleteQueue.WaitForPolledResult(context, *this); - if (!result) - { - throw Azure::Core::OperationCancelledException("Close operation was cancelled."); - } - m_isOpen = false; - } - -#if ENABLE_UAMQP - void TransportImpl::OnOpenCompleteFn(void* context, IO_OPEN_RESULT ioOpenResult) - { - TransportImpl* transport = reinterpret_cast(context); - Network::_internal::TransportOpenStatus openResult{ - Network::_internal::TransportOpenStatus::Error}; - switch (ioOpenResult) - { - - case IO_OPEN_RESULT_INVALID: - openResult = Network::_internal::TransportOpenStatus::Invalid; - break; - case IO_OPEN_CANCELLED: - openResult = Network::_internal::TransportOpenStatus::Cancelled; - break; - case IO_OPEN_ERROR: - openResult = Network::_internal::TransportOpenStatus::Error; - break; + // This constructor is used by the SocketTransport and TlsTransport classes to construct a + // transport around an already constructed XIO transport. + TransportImpl::TransportImpl(XIO_HANDLE handle, Network::_internal::TransportEvents* eventHandler) + : m_xioInstance{handle}, m_eventHandler{eventHandler} + { + assert(handle != nullptr); + EnsureGlobalStateInitialized(); + } - case IO_OPEN_OK: - openResult = Network::_internal::TransportOpenStatus::Ok; - break; - } - transport->m_openCompleteQueue.CompleteOperation(openResult); - } + TransportImpl::~TransportImpl() {} - void TransportImpl::OnBytesReceivedFn( - void* context, - unsigned char const* buffer, - size_t size) - { - TransportImpl* transport = reinterpret_cast(context); - if (transport->m_eventHandler) - { - transport->m_eventHandler->OnBytesReceived(transport->shared_from_this(), buffer, size); - } - } + template struct CloseCallbackWrapper + { + static void OnOperation(CompleteFn onComplete) { onComplete(); } + }; - void TransportImpl::OnIOErrorFn(void* context) - { - TransportImpl* transport = reinterpret_cast(context); - if (transport->m_eventHandler) - { + void TransportImpl::OnCloseCompleteFn(void* context) + { + TransportImpl* transport = reinterpret_cast(context); + transport->m_closeCompleteQueue.CompleteOperation(true); + } + void TransportImpl::Close(Context const& context) + { + if (!m_isOpen) + { + throw std::logic_error("Cannot close an unopened transport."); + } + if (m_xioInstance) + { + if (xio_close(m_xioInstance.get(), OnCloseCompleteFn, this)) + { + throw std::runtime_error("Failed to close the transport."); + } + m_xioInstance = nullptr; + } + auto result = m_closeCompleteQueue.WaitForPolledResult(context, *this); + if (!result) + { + throw Azure::Core::OperationCancelledException("Close operation was cancelled."); + } + m_isOpen = false; + } - transport->m_eventHandler->OnIOError(); - } - } -#endif + void TransportImpl::OnOpenCompleteFn(void* context, IO_OPEN_RESULT ioOpenResult) + { + TransportImpl* transport = reinterpret_cast(context); + Network::_internal::TransportOpenStatus openResult{ + Network::_internal::TransportOpenStatus::Error}; + switch (ioOpenResult) + { + + case IO_OPEN_RESULT_INVALID: + openResult = Network::_internal::TransportOpenStatus::Invalid; + break; + case IO_OPEN_CANCELLED: + openResult = Network::_internal::TransportOpenStatus::Cancelled; + break; + case IO_OPEN_ERROR: + openResult = Network::_internal::TransportOpenStatus::Error; + break; + + case IO_OPEN_OK: + openResult = Network::_internal::TransportOpenStatus::Ok; + break; + } + transport->m_openCompleteQueue.CompleteOperation(openResult); + } - _internal::TransportOpenStatus TransportImpl::Open(Context const& context) - { - if (m_isOpen) - { - throw std::logic_error("Cannot open an opened transport."); - } -#if ENABLE_UAMQP - if (xio_open( - m_xioInstance.get(), - OnOpenCompleteFn, - this, - OnBytesReceivedFn, - this, - OnIOErrorFn, - this)) - { - return _internal::TransportOpenStatus::Error; - } -#endif - m_isOpen = true; - auto result = m_openCompleteQueue.WaitForPolledResult(context, *this); - if (result) - { - return std::get<0>(*result); - } - throw Azure::Core::OperationCancelledException("Open operation was cancelled."); - } + void TransportImpl::OnBytesReceivedFn(void* context, unsigned char const* buffer, size_t size) + { + TransportImpl* transport = reinterpret_cast(context); + if (transport->m_eventHandler) + { + transport->m_eventHandler->OnBytesReceived(transport->shared_from_this(), buffer, size); + } + } -#if ENABLE_UAMQP - template struct SendCallbackRewriter - { - static void OnOperation(CompleteFn onComplete, IO_SEND_RESULT sendResult) - { - Network::_internal::TransportSendStatus result{ - Network::_internal::TransportSendStatus::Ok}; - switch (sendResult) - { + void TransportImpl::OnIOErrorFn(void* context) + { + TransportImpl* transport = reinterpret_cast(context); + if (transport->m_eventHandler) + { - case IO_SEND_RESULT_INVALID: - result = Network::_internal::TransportSendStatus::Invalid; - break; - case IO_SEND_CANCELLED: - result = Network::_internal::TransportSendStatus::Cancelled; - break; - case IO_SEND_ERROR: - result = Network::_internal::TransportSendStatus::Error; - break; + transport->m_eventHandler->OnIOError(); + } + } - case IO_SEND_OK: - result = Network::_internal::TransportSendStatus::Ok; - break; - } - onComplete(result); - } - }; -#endif + _internal::TransportOpenStatus TransportImpl::Open(Context const& context) + { + if (m_isOpen) + { + throw std::logic_error("Cannot open an opened transport."); + } + if (xio_open( + m_xioInstance.get(), + OnOpenCompleteFn, + this, + OnBytesReceivedFn, + this, + OnIOErrorFn, + this)) + { + return _internal::TransportOpenStatus::Error; + } + m_isOpen = true; + auto result = m_openCompleteQueue.WaitForPolledResult(context, *this); + if (result) + { + return std::get<0>(*result); + } + throw Azure::Core::OperationCancelledException("Open operation was cancelled."); + } - bool TransportImpl::Send( - unsigned char* buffer, - size_t size, - Network::_internal::Transport::TransportSendCompleteFn sendComplete) const - { -#if ENABLE_UAMQP - auto operation{std::make_unique>>(sendComplete)}; - if (xio_send( - m_xioInstance.get(), - buffer, - size, - std::remove_pointer::type::OnOperationFn, - operation.release())) - { - return false; - } -#else - (void)size; - (void)buffer; - (void)sendComplete; -#endif - return true; - } + template struct SendCallbackRewriter + { + static void OnOperation(CompleteFn onComplete, IO_SEND_RESULT sendResult) + { + Network::_internal::TransportSendStatus result{Network::_internal::TransportSendStatus::Ok}; + switch (sendResult) + { + + case IO_SEND_RESULT_INVALID: + result = Network::_internal::TransportSendStatus::Invalid; + break; + case IO_SEND_CANCELLED: + result = Network::_internal::TransportSendStatus::Cancelled; + break; + case IO_SEND_ERROR: + result = Network::_internal::TransportSendStatus::Error; + break; + + case IO_SEND_OK: + result = Network::_internal::TransportSendStatus::Ok; + break; + } + onComplete(result); + } + }; + + bool TransportImpl::Send( + unsigned char* buffer, + size_t size, + Network::_internal::Transport::TransportSendCompleteFn sendComplete) const + { + auto operation{std::make_unique>>(sendComplete)}; + if (xio_send( + m_xioInstance.get(), + buffer, + size, + std::remove_pointer::type::OnOperationFn, + operation.release())) + { + return false; + } + return true; + } - void TransportImpl::Poll() const - { -#if ENABLE_UAMQP - if (m_xioInstance) - { - xio_dowork(m_xioInstance.get()); - } -#endif - } + void TransportImpl::Poll() const + { + if (m_xioInstance) + { + xio_dowork(m_xioInstance.get()); + } + } }}}}} // namespace Azure::Core::Amqp::Network::_detail +#endif // ENABLE_UAMQP diff --git a/sdk/core/azure-core-amqp/test/ut/CMakeLists.txt b/sdk/core/azure-core-amqp/test/ut/CMakeLists.txt index 96d62945b7..d72886afe6 100644 --- a/sdk/core/azure-core-amqp/test/ut/CMakeLists.txt +++ b/sdk/core/azure-core-amqp/test/ut/CMakeLists.txt @@ -13,6 +13,13 @@ include(AzureBuildTargetForCI) include(GoogleTest) # Unit Tests + +IF (USE_UAMQP) +set(UAMQP_ONLY_TESTS + transport_tests.cpp +) +ENDIF() + add_executable(azure-core-amqp-tests amqp_header_tests.cpp amqp_message_tests.cpp @@ -29,8 +36,11 @@ add_executable(azure-core-amqp-tests message_source_target.cpp mock_amqp_server.hpp session_tests.cpp - transport_tests.cpp - "amqp_performative_tests.cpp") + amqp_performative_tests.cpp + ${UAMQP_ONLY_TESTS} +) + + add_dependencies(azure-core-amqp-tests Azure::azure-core-amqp) target_compile_definitions(azure-core-amqp-tests PRIVATE _azure_BUILDING_TESTS) diff --git a/sdk/core/azure-core-amqp/test/ut/claim_based_security_tests.cpp b/sdk/core/azure-core-amqp/test/ut/claim_based_security_tests.cpp index c28ed52357..f2357f42a0 100644 --- a/sdk/core/azure-core-amqp/test/ut/claim_based_security_tests.cpp +++ b/sdk/core/azure-core-amqp/test/ut/claim_based_security_tests.cpp @@ -77,6 +77,7 @@ namespace Azure { namespace Core { namespace Amqp { namespace Tests { #if !defined(AZ_PLATFORM_MAC) TEST_F(TestCbs, CbsOpenNoListener) { +#if ENABLE_UAMQP MessageTests::AmqpServerMock mockServer; ConnectionOptions options; options.EnableTrace = true; @@ -89,10 +90,14 @@ namespace Azure { namespace Core { namespace Amqp { namespace Tests { EXPECT_EQ(CbsOpenResult::Error, cbs.Open()); } +#else + EXPECT_TRUE(false); +#endif } TEST_F(TestCbs, CbsOpen) { +#if ENABLE_UAMQP MessageTests::AmqpServerMock mockServer; mockServer.EnableTrace(false); @@ -118,10 +123,14 @@ namespace Azure { namespace Core { namespace Amqp { namespace Tests { } } mockServer.StopListening(); +#else + EXPECT_TRUE(false); +#endif } TEST_F(TestCbs, CbsCancelledOpen) { +#if ENABLE_UAMQP MessageTests::AmqpServerMock mockServer; mockServer.EnableTrace(false); @@ -144,6 +153,9 @@ namespace Azure { namespace Core { namespace Amqp { namespace Tests { EXPECT_EQ(CbsOpenResult::Cancelled, openResult); } mockServer.StopListening(); +#else + EXPECT_TRUE(false); +#endif } #endif // !defined(AZ_PLATFORM_MAC) @@ -151,6 +163,7 @@ namespace Azure { namespace Core { namespace Amqp { namespace Tests { #if !defined(AZ_PLATFORM_MAC) TEST_F(TestCbs, CbsOpenAndPut) { +#if ENABLE_UAMQP MessageTests::AmqpServerMock mockServer; ConnectionOptions options; @@ -176,12 +189,16 @@ namespace Azure { namespace Core { namespace Amqp { namespace Tests { } mockServer.StopListening(); +#else + EXPECT_TRUE(false); +#endif } #endif // !defined(AZ_PLATFORM_MAC) #if !defined(AZ_PLATFORM_MAC) TEST_F(TestCbs, CbsOpenAndPutError) { +#if ENABLE_UAMQP { MessageTests::AmqpServerMock mockServer; @@ -208,10 +225,14 @@ namespace Azure { namespace Core { namespace Amqp { namespace Tests { mockServer.StopListening(); } +#else + EXPECT_TRUE(false); +#endif } TEST_F(TestCbs, CbsOpenAndPutCancelled) { +#if ENABLE_UAMQP { MessageTests::AmqpServerMock mockServer; @@ -246,6 +267,9 @@ namespace Azure { namespace Core { namespace Amqp { namespace Tests { mockServer.StopListening(); } +#else + EXPECT_TRUE(false); +#endif } #endif // !defined(AZ_PLATFORM_MAC) diff --git a/sdk/core/azure-core-amqp/test/ut/connection_string_tests.cpp b/sdk/core/azure-core-amqp/test/ut/connection_string_tests.cpp index e9e69a80a8..0ea52d668d 100644 --- a/sdk/core/azure-core-amqp/test/ut/connection_string_tests.cpp +++ b/sdk/core/azure-core-amqp/test/ut/connection_string_tests.cpp @@ -48,7 +48,9 @@ TEST_F(ConnectionStringTest, ServiceBusSasConnectionGood) EXPECT_EQ("{ACCESS_KEY}=", credential.GetSharedAccessKey()); { #if !defined(AZ_PLATFORM_MAC) +#if ENABLE_UAMQP auto xport = credential.GetTransport(); +#endif #endif // !defined(AZ_PLATFORM_MAC) // Generate a SAS token which expires in 60 seconds. diff --git a/sdk/core/azure-core-amqp/test/ut/connection_tests.cpp b/sdk/core/azure-core-amqp/test/ut/connection_tests.cpp index 4d1c30b70c..8e008ec4b0 100644 --- a/sdk/core/azure-core-amqp/test/ut/connection_tests.cpp +++ b/sdk/core/azure-core-amqp/test/ut/connection_tests.cpp @@ -46,6 +46,7 @@ namespace Azure { namespace Core { namespace Amqp { namespace Tests { Azure::Core::Amqp::_internal::Connection connection("localhost", nullptr, connectionOptions); } +#if ENABLE_UAMQP { Azure::Core::Amqp::_internal::ConnectionOptions options; auto socketTransport{Azure::Core::Amqp::Network::_internal::SocketTransportFactory::Create( @@ -54,6 +55,7 @@ namespace Azure { namespace Core { namespace Amqp { namespace Tests { Azure::Core::Amqp::_internal::Connection connection( socketTransport, options, nullptr, nullptr); } +#endif } TEST_F(TestConnections, ConnectionAttributes) @@ -82,9 +84,10 @@ namespace Azure { namespace Core { namespace Amqp { namespace Tests { auto maxFrameSize = connection.GetMaxFrameSize(); (void)maxFrameSize; EXPECT_EQ(1024 * 64, connection.GetMaxFrameSize()); - +#if ENABLE_UAMQP EXPECT_NO_THROW( connection.GetRemoteMaxFrameSize()); // Likely doesn't work unless there's a remote. +#endif } { @@ -106,22 +109,28 @@ namespace Azure { namespace Core { namespace Amqp { namespace Tests { options.MaxChannelCount = 128; Azure::Core::Amqp::_internal::Connection connection("localhost", nullptr, options); +#if ENABLE_UAMQP // Ratio must be a number between 0 and 1. EXPECT_NO_THROW(connection.SetIdleEmptyFrameSendPercentage(0.5)); +#endif } { Azure::Core::Amqp::_internal::ConnectionOptions options; options.MaxChannelCount = 128; - options.Properties["test"] = "test"; + options.Properties[Azure::Core::Amqp::Models::AmqpSymbol{"test"}] = "test"; Azure::Core::Amqp::_internal::Connection connection("localhost", nullptr, options); - EXPECT_EQ(Azure::Core::Amqp::Models::AmqpValue{"test"}, connection.GetProperties()["test"]); + GTEST_LOG_(INFO) << connection.GetProperties(); + EXPECT_EQ( + Azure::Core::Amqp::Models::AmqpValue{"test"}, + connection.GetProperties()[Azure::Core::Amqp::Models::AmqpSymbol{"test"}]); } } TEST_F(TestConnections, ConnectionOpenClose) { +#if ENABLE_UAMQP class TestListener : public Azure::Core::Amqp::Network::_detail::SocketListenerEvents { public: std::shared_ptr WaitForResult( @@ -174,6 +183,18 @@ namespace Azure { namespace Core { namespace Amqp { namespace Tests { connection.Close("xxx", "yyy", {}); listener.Stop(); } +#else + // Create a connection + Azure::Core::Amqp::_internal::ConnectionOptions connectionOptions; + connectionOptions.Port = 25672; + Azure::Core::Amqp::_internal::Connection connection("localhost", nullptr, connectionOptions); + + // Open the connection + connection.Open(); + + connection.Close("", "", {}); + +#endif } #endif // !defined(AZ_PLATFORM_MAC) diff --git a/sdk/core/azure-core-amqp/test/ut/link_tests.cpp b/sdk/core/azure-core-amqp/test/ut/link_tests.cpp index 7ba3d1a69f..52de47d778 100644 --- a/sdk/core/azure-core-amqp/test/ut/link_tests.cpp +++ b/sdk/core/azure-core-amqp/test/ut/link_tests.cpp @@ -118,7 +118,7 @@ namespace Azure { namespace Core { namespace Amqp { namespace Tests { EXPECT_ANY_THROW(link.ResetLinkCredit(92, true)); } } - +#if ENABLE_UAMQP class LinkSocketListenerEvents : public Azure::Core::Amqp::Network::_detail::SocketListenerEvents, public Azure::Core::Amqp::_internal::ConnectionEvents, @@ -248,9 +248,11 @@ namespace Azure { namespace Core { namespace Amqp { namespace Tests { } } }; +#endif TEST_F(TestLinks, LinkAttachDetach) { +#if ENABLE_UAMQP LinkSocketListenerEvents events; uint16_t testPort = FindAvailableSocket(); @@ -276,10 +278,14 @@ namespace Azure { namespace Core { namespace Amqp { namespace Tests { } events.Cleanup(); listener.Stop(); +#else + EXPECT_TRUE(false); +#endif } TEST_F(TestLinks, LinkAttachDetachMultipleOneSession) { +#if ENABLE_UAMQP class MySessionListener final : public MessageTests::MockServiceEndpoint { public: MySessionListener(MessageTests::MockServiceEndpointOptions const& options) @@ -436,6 +442,9 @@ namespace Azure { namespace Core { namespace Amqp { namespace Tests { keepAliveLink.Detach(true, "", "", {}); server.StopListening(); +#else + EXPECT_TRUE(false); +#endif } #endif // defined(AZ_PLATFORM_MAC) }}}} // namespace Azure::Core::Amqp::Tests diff --git a/sdk/core/azure-core-amqp/test/ut/management_tests.cpp b/sdk/core/azure-core-amqp/test/ut/management_tests.cpp index 6ba82cbddc..a286a7b638 100644 --- a/sdk/core/azure-core-amqp/test/ut/management_tests.cpp +++ b/sdk/core/azure-core-amqp/test/ut/management_tests.cpp @@ -19,7 +19,8 @@ namespace Azure { namespace Core { namespace Amqp { namespace Tests { protected: void SetUp() override {} void TearDown() override - { // When the test is torn down, the global state MUST be idle. If it is not, something leaked. + { // When the test is torn down, the global state MUST be idle. If it is not, something + // leaked. Azure::Core::Amqp::Common::_detail::GlobalStateHolder::GlobalStateInstance()->AssertIdle(); } }; @@ -53,8 +54,8 @@ namespace Azure { namespace Core { namespace Amqp { namespace Tests { EXPECT_EQ(openResult, ManagementOpenStatus::Error); } +#if ENABLE_UAMQP namespace { - class ManagementServiceEndpoint final : public MessageTests::MockServiceEndpoint { public: void SetStatusCode(AmqpValue expectedStatusCode) @@ -127,8 +128,8 @@ namespace Azure { namespace Core { namespace Amqp { namespace Tests { } responseMessage.Properties.CorrelationId = requestCorrelationId; - // Block until the send is completed. Note: Do *not* use the listener context to ensure - // that the send is completed. + // Block until the send is completed. Note: Do *not* use the listener context to + // ensure that the send is completed. auto sendResult(GetMessageSender().Send(responseMessage)); if (std::get<0>(sendResult) != MessageSendStatus::Ok) { @@ -144,9 +145,11 @@ namespace Azure { namespace Core { namespace Amqp { namespace Tests { std::string m_expectedStatusDescriptionName = "statusDescription"; }; } // namespace +#endif TEST_F(TestManagement, ManagementOpenClose) { +#if ENABLE_UAMQP MessageTests::AmqpServerMock mockServer; MessageTests::MockServiceEndpointOptions managementEndpointOptions; managementEndpointOptions.EnableTrace = true; @@ -170,10 +173,14 @@ namespace Azure { namespace Core { namespace Amqp { namespace Tests { management.Close(); mockServer.StopListening(); +#else + EXPECT_TRUE(false); +#endif } TEST_F(TestManagement, ManagementOpenCloseAuthenticated) { +#if ENABLE_UAMQP MessageTests::AmqpServerMock mockServer; MessageTests::MockServiceEndpointOptions managementEndpointOptions; managementEndpointOptions.EnableTrace = true; @@ -202,10 +209,14 @@ namespace Azure { namespace Core { namespace Amqp { namespace Tests { management.Close(); mockServer.StopListening(); +#else + EXPECT_TRUE(false); +#endif } TEST_F(TestManagement, ManagementOpenCloseAuthenticatedFail) { +#if ENABLE_UAMQP MessageTests::AmqpServerMock mockServer; MessageTests::MockServiceEndpointOptions managementEndpointOptions; managementEndpointOptions.EnableTrace = true; @@ -245,10 +256,14 @@ namespace Azure { namespace Core { namespace Amqp { namespace Tests { GTEST_LOG_(INFO) << "Caught exception: " << e.what(); } mockServer.StopListening(); +#else + EXPECT_TRUE(false); +#endif } TEST_F(TestManagement, ManagementOpenCloseError) { +#if ENABLE_UAMQP MessageTests::AmqpServerMock mockServer; MessageTests::MockServiceEndpointOptions managementEndpointOptions; managementEndpointOptions.EnableTrace = true; @@ -272,10 +287,13 @@ namespace Azure { namespace Core { namespace Amqp { namespace Tests { EXPECT_THROW(management.Close(), std::runtime_error); mockServer.StopListening(); +#else + EXPECT_TRUE(false); +#endif } #endif // !defined(AZ_PLATFORM_MAC) #if !defined(AZ_PLATFORM_MAC) - +#if ENABLE_UAMQP namespace { class NullResponseManagementServiceEndpoint final : public MessageTests::MockServiceEndpoint { @@ -296,9 +314,11 @@ namespace Azure { namespace Core { namespace Amqp { namespace Tests { } }; } // namespace +#endif TEST_F(TestManagement, ManagementRequestResponse) { +#if ENABLE_UAMQP MessageTests::AmqpServerMock mockServer; MessageTests::MockServiceEndpointOptions managementEndpointOptions; managementEndpointOptions.EnableTrace = true; @@ -340,9 +360,13 @@ namespace Azure { namespace Core { namespace Amqp { namespace Tests { management.Close(); mockServer.StopListening(); +#else + EXPECT_TRUE(false); +#endif } TEST_F(TestManagement, ManagementRequestResponseSimple) { +#if ENABLE_UAMQP MessageTests::AmqpServerMock mockServer; auto managementEndpoint = std::make_shared(MessageTests::MockServiceEndpointOptions{}); @@ -373,10 +397,14 @@ namespace Azure { namespace Core { namespace Amqp { namespace Tests { management.Close(); mockServer.StopListening(); +#else + EXPECT_TRUE(false); +#endif } TEST_F(TestManagement, ManagementRequestResponseExpect500) { +#if ENABLE_UAMQP MessageTests::AmqpServerMock mockServer; auto managementEndpoint @@ -411,9 +439,13 @@ namespace Azure { namespace Core { namespace Amqp { namespace Tests { management.Close(); mockServer.StopListening(); +#else + EXPECT_TRUE(false); +#endif } TEST_F(TestManagement, ManagementRequestResponseBogusStatusCode) { +#if ENABLE_UAMQP // Send a response with a bogus status code type. MessageTests::AmqpServerMock mockServer; auto managementEndpoint @@ -429,8 +461,8 @@ namespace Azure { namespace Core { namespace Amqp { namespace Tests { options.EnableTrace = true; ManagementClient management(session.CreateManagementClient("Test", options)); - // Set the response status code to something other than an int - that will cause the response - // to be rejected by the management client. + // Set the response status code to something other than an int - that will cause the + // response to be rejected by the management client. managementEndpoint->SetStatusCode(500u); managementEndpoint->SetStatusDescription("Bad Things Happened."); mockServer.StartListening(); @@ -450,9 +482,13 @@ namespace Azure { namespace Core { namespace Amqp { namespace Tests { management.Close(); mockServer.StopListening(); +#else + EXPECT_TRUE(false); +#endif } TEST_F(TestManagement, ManagementRequestResponseBogusStatusName) { +#if ENABLE_UAMQP // Send a response to the request with a bogus status code name. MessageTests::AmqpServerMock mockServer; auto managementEndpoint @@ -480,8 +516,8 @@ namespace Azure { namespace Core { namespace Amqp { namespace Tests { ManagementClient management(session.CreateManagementClient("Test", options, &managementEvents)); - // Set the response status code to something other than an int - that will cause the response - // to be rejected by the management client. + // Set the response status code to something other than an int - that will cause the + // response to be rejected by the management client. managementEndpoint->SetStatusCode(500); managementEndpoint->SetStatusCodeName("status-code"); managementEndpoint->SetStatusDescription("Bad Things Happened."); @@ -504,9 +540,13 @@ namespace Azure { namespace Core { namespace Amqp { namespace Tests { management.Close(); mockServer.StopListening(); +#else + EXPECT_TRUE(false); +#endif } TEST_F(TestManagement, ManagementRequestResponseBogusStatusName2) { +#if ENABLE_UAMQP // Send a response to the request with a bogus status code name. MessageTests::AmqpServerMock mockServer; auto managementEndpoint @@ -524,8 +564,8 @@ namespace Azure { namespace Core { namespace Amqp { namespace Tests { ManagementClient management(session.CreateManagementClient("Test", options)); - // Set the response status code to something other than an int - that will cause the response - // to be rejected by the management client. + // Set the response status code to something other than an int - that will cause the + // response to be rejected by the management client. managementEndpoint->SetStatusCode(235); managementEndpoint->SetStatusCodeName("status-code"); managementEndpoint->SetStatusDescription("Bad Things Happened.."); @@ -544,10 +584,14 @@ namespace Azure { namespace Core { namespace Amqp { namespace Tests { management.Close(); mockServer.StopListening(); +#else + EXPECT_TRUE(false); +#endif } TEST_F(TestManagement, ManagementRequestResponseUnknownOperationName) { +#if ENABLE_UAMQP // Send a management request with an unknown operation name. MessageTests::AmqpServerMock mockServer; MessageTests::MockServiceEndpointOptions managementEndpointOptions; @@ -587,6 +631,9 @@ namespace Azure { namespace Core { namespace Amqp { namespace Tests { management.Close(); mockServer.StopListening(); +#else + EXPECT_TRUE(false); +#endif } #endif // !defined(AZ_PLATFORM_MAC) }}}} // namespace Azure::Core::Amqp::Tests diff --git a/sdk/core/azure-core-amqp/test/ut/message_sender_receiver.cpp b/sdk/core/azure-core-amqp/test/ut/message_sender_receiver.cpp index 5463b1549e..3298729194 100644 --- a/sdk/core/azure-core-amqp/test/ut/message_sender_receiver.cpp +++ b/sdk/core/azure-core-amqp/test/ut/message_sender_receiver.cpp @@ -30,7 +30,8 @@ namespace Azure { namespace Core { namespace Amqp { namespace Tests { protected: void SetUp() override {} void TearDown() override - { // When the test is torn down, the global state MUST be idle. If it is not, something leaked. + { // When the test is torn down, the global state MUST be idle. If it is not, something + // leaked. Azure::Core::Amqp::Common::_detail::GlobalStateHolder::GlobalStateInstance()->AssertIdle(); } }; @@ -93,11 +94,11 @@ namespace Azure { namespace Core { namespace Amqp { namespace Tests { Session session{connection.CreateSession()}; { - MessageSender sender(session.CreateMessageSender("MySource", {}, nullptr)); + MessageSender sender(session.CreateMessageSender("MySource", {})); } { - MessageSender sender1(session.CreateMessageSender("MySource", {}, nullptr)); - MessageSender sender2(session.CreateMessageSender("MySource", {}, nullptr)); + MessageSender sender1(session.CreateMessageSender("MySource", {})); + MessageSender sender2(session.CreateMessageSender("MySource", {})); } GTEST_LOG_(INFO) << _internal::MessageSenderState::Invalid << _internal::MessageSenderState::Closing @@ -114,12 +115,13 @@ namespace Azure { namespace Core { namespace Amqp { namespace Tests { { MessageSenderOptions options; options.EnableTrace = true; - MessageSender sender(session.CreateMessageSender("MySource", options, nullptr)); + MessageSender sender(session.CreateMessageSender("MySource", options)); } } TEST_F(TestMessageSendReceive, ReceiverOpenClose) { +#if ENABLE_UAMQP MessageTests::AmqpServerMock mockServer; ConnectionOptions connectionOptions; @@ -176,10 +178,14 @@ namespace Azure { namespace Core { namespace Amqp { namespace Tests { mockServer.StopListening(); context.Cancel(); +#else + EXPECT_TRUE(false); +#endif } TEST_F(TestMessageSendReceive, SenderOpenClose) { +#if ENABLE_UAMQP class SenderLinkEndpoint : public MessageTests::MockServiceEndpoint { public: SenderLinkEndpoint( @@ -226,10 +232,14 @@ namespace Azure { namespace Core { namespace Amqp { namespace Tests { sender.Close(); } mockServer.StopListening(); +#else + EXPECT_TRUE(false); +#endif } TEST_F(TestMessageSendReceive, TestLocalhostVsTls) { +#if ENABLE_UAMQP MessageTests::AmqpServerMock mockServer(5671); mockServer.StartListening(); @@ -273,10 +283,14 @@ namespace Azure { namespace Core { namespace Amqp { namespace Tests { EXPECT_TRUE(sender.Open()); } mockServer.StopListening(); +#else + EXPECT_TRUE(false); +#endif } TEST_F(TestMessageSendReceive, SenderSendAsync) { +#if ENABLE_UAMQP class SenderLinkEndpoint : public MessageTests::MockServiceEndpoint { public: SenderLinkEndpoint( @@ -359,10 +373,14 @@ namespace Azure { namespace Core { namespace Amqp { namespace Tests { } receiveContext.Cancel(); mockServer.StopListening(); +#else + EXPECT_TRUE(false); +#endif } TEST_F(TestMessageSendReceive, SenderSendSync) { +#if ENABLE_UAMQP class SenderLinkEndpoint final : public MessageTests::MockServiceEndpoint { public: SenderLinkEndpoint( @@ -427,10 +445,14 @@ namespace Azure { namespace Core { namespace Amqp { namespace Tests { } receiveContext.Cancel(); mockServer.StopListening(); +#else + EXPECT_TRUE(false); +#endif } TEST_F(TestMessageSendReceive, AuthenticatedSender) { +#if ENABLE_UAMQP class ReceiverServiceEndpoint : public MessageTests::MockServiceEndpoint { public: ReceiverServiceEndpoint( @@ -491,10 +513,14 @@ namespace Azure { namespace Core { namespace Amqp { namespace Tests { sender.Close(); server.StopListening(); +#else + EXPECT_TRUE(false); +#endif } TEST_F(TestMessageSendReceive, AuthenticatedSenderAzureToken) { +#if ENABLE_UAMQP class AzureTokenCredential : public Azure::Core::Credentials::TokenCredential { Azure::Core::Credentials::AccessToken GetToken( const Azure::Core::Credentials::TokenRequestContext& requestContext, @@ -568,10 +594,14 @@ namespace Azure { namespace Core { namespace Amqp { namespace Tests { sender.Close(); server.StopListening(); +#else + EXPECT_TRUE(false); +#endif } TEST_F(TestMessageSendReceive, AuthenticatedReceiver) { +#if ENABLE_UAMQP class ReceiverServiceEndpoint : public MessageTests::MockServiceEndpoint { public: ReceiverServiceEndpoint( @@ -689,10 +719,14 @@ namespace Azure { namespace Core { namespace Amqp { namespace Tests { } receiver.Close(); server.StopListening(); +#else + EXPECT_TRUE(false); +#endif } TEST_F(TestMessageSendReceive, AuthenticatedReceiverAzureToken) { +#if ENABLE_UAMQP class ReceiverServiceEndpoint : public MessageTests::MockServiceEndpoint { public: ReceiverServiceEndpoint( @@ -817,10 +851,14 @@ namespace Azure { namespace Core { namespace Amqp { namespace Tests { } receiver.Close(); server.StopListening(); +#else + EXPECT_TRUE(false); +#endif } TEST_F(TestMessageSendReceive, AuthenticatedReceiverTryReceive) { +#if ENABLE_UAMQP class ReceiverServiceEndpoint final : public MessageTests::MockServiceEndpoint { public: ReceiverServiceEndpoint( @@ -918,6 +956,9 @@ namespace Azure { namespace Core { namespace Amqp { namespace Tests { } receiver.Close(); server.StopListening(); +#else + EXPECT_TRUE(false); +#endif } #endif // !defined(AZ_PLATFORM_MAC) diff --git a/sdk/core/azure-core-amqp/test/ut/mock_amqp_server.hpp b/sdk/core/azure-core-amqp/test/ut/mock_amqp_server.hpp index 99304fdd3a..d629d5ca82 100644 --- a/sdk/core/azure-core-amqp/test/ut/mock_amqp_server.hpp +++ b/sdk/core/azure-core-amqp/test/ut/mock_amqp_server.hpp @@ -22,6 +22,8 @@ #define NEW_MOCK_SERVER 1 +#if ENABLE_UAMQP + namespace Azure { namespace Core { namespace Amqp { namespace Tests { extern uint16_t FindAvailableSocket(); @@ -781,3 +783,4 @@ namespace Azure { namespace Core { namespace Amqp { namespace Tests { }; } // namespace MessageTests }}}} // namespace Azure::Core::Amqp::Tests +#endif // ENABLE_UAMQP diff --git a/sdk/core/azure-core-amqp/test/ut/session_tests.cpp b/sdk/core/azure-core-amqp/test/ut/session_tests.cpp index bfb9ccd958..17a63563ef 100644 --- a/sdk/core/azure-core-amqp/test/ut/session_tests.cpp +++ b/sdk/core/azure-core-amqp/test/ut/session_tests.cpp @@ -165,6 +165,7 @@ namespace Azure { namespace Core { namespace Amqp { namespace Tests { #if !defined(AZ_PLATFORM_MAC) TEST_F(TestSessions, SessionBeginEnd) { +#if ENABLE_UAMQP class TestListenerEvents : public Network::_detail::SocketListenerEvents { public: std::shared_ptr WaitForResult( @@ -213,11 +214,14 @@ namespace Azure { namespace Core { namespace Amqp { namespace Tests { } listener.Stop(); +#else + EXPECT_TRUE(false); +#endif } TEST_F(TestSessions, MultipleSessionBeginEnd) { - +#if ENABLE_UAMQP MessageTests::AmqpServerMock mockServer; mockServer.EnableTrace(false); mockServer.StartListening(); @@ -277,6 +281,9 @@ namespace Azure { namespace Core { namespace Amqp { namespace Tests { connection.Close(); mockServer.StopListening(); +#else + EXPECT_TRUE(false); +#endif } #endif // !AZ_PLATFORM_MAC }}}} // namespace Azure::Core::Amqp::Tests diff --git a/sdk/core/azure-core/inc/azure/core/etag.hpp b/sdk/core/azure-core/inc/azure/core/etag.hpp index eec3945cab..bce0613c26 100644 --- a/sdk/core/azure-core/inc/azure/core/etag.hpp +++ b/sdk/core/azure-core/inc/azure/core/etag.hpp @@ -178,10 +178,10 @@ class ETag final { return weak; } - /** - * @brief #Azure::ETag representing everything. - * @note The any #Azure::ETag is *, (unquoted). It is NOT the same as "*". + * @brief Azure::ETag representing everything. + * + * @remark The any Azure::ETag is an unquoted asterisk character (*). It is NOT the same as "*". */ static const ETag& Any(); }; diff --git a/sdk/eventhubs/azure-messaging-eventhubs/CMakeLists.txt b/sdk/eventhubs/azure-messaging-eventhubs/CMakeLists.txt index 0ea0b8e101..5d8d833a9c 100644 --- a/sdk/eventhubs/azure-messaging-eventhubs/CMakeLists.txt +++ b/sdk/eventhubs/azure-messaging-eventhubs/CMakeLists.txt @@ -51,6 +51,7 @@ elseif(NOT AZ_ALL_LIBRARIES) endif() + set( AZURE_MESSAGING_EVENTHUBS_HEADER inc/azure/messaging/eventhubs.hpp @@ -112,6 +113,12 @@ target_link_libraries(azure-messaging-eventhubs PUBLIC Azure::azure-core Azure:: target_compile_definitions(azure-messaging-eventhubs PRIVATE _azure_BUILDING_SDK) +if(USE_RUST_AMQP) + target_compile_definitions(azure-messaging-eventhubs PRIVATE ENABLE_RUST_AMQP) +else() + target_compile_definitions(azure-messaging-eventhubs PRIVATE ENABLE_UAMQP) +endif() + # coverage. Has no effect if BUILD_CODE_COVERAGE is OFF create_code_coverage(eventhubs azure-messaging-eventhubs azure-messaging-eventhubs-test "tests?/*;samples?/*") diff --git a/sdk/eventhubs/azure-messaging-eventhubs/src/producer_client.cpp b/sdk/eventhubs/azure-messaging-eventhubs/src/producer_client.cpp index e19bd38238..98054ab9c0 100644 --- a/sdk/eventhubs/azure-messaging-eventhubs/src/producer_client.cpp +++ b/sdk/eventhubs/azure-messaging-eventhubs/src/producer_client.cpp @@ -181,7 +181,7 @@ namespace Azure { namespace Messaging { namespace EventHubs { senderOptions.MaxMessageSize = m_producerClientOptions.MaxMessageSize; Azure::Core::Amqp::_internal::MessageSender sender - = GetSession(partitionId).CreateMessageSender(targetUrl, senderOptions, nullptr); + = GetSession(partitionId).CreateMessageSender(targetUrl, senderOptions); auto openResult{sender.Open(context)}; if (openResult) {