From 6b1a06bd429f395891a3230cad92e674dcbbb0d2 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Sun, 15 May 2022 15:54:24 +0400 Subject: [PATCH] Revert "Merge pull request #1202 from ArminShoeibi/feat/file-scoped-namespaces" This reverts commit 1713f50eb2dc52a97184f3857f70841dd55b5bef, reversing changes made to f8c7b9d1238a779e479e328647e1f7e21ba3f624. It's a nice feature but it makes it impossible to backport things from main to 7.x and 6.x unless those branches also adopt it. So file-scoped namespaces are not necessary worth the backporting pain for library maintainers. Conflicts: projects/RabbitMQ.Client/client/api/DefaultEndpointResolver.cs projects/RabbitMQ.Client/client/impl/AutorecoveringConnection.Recording.cs projects/RabbitMQ.Client/client/impl/SocketFrameHandler.cs --- .../FrameworkExtension/DictionaryExtension.cs | 14 +- .../FrameworkExtension/StringExtension.cs | 14 +- .../client/api/AmqpTcpEndpoint.cs | 409 ++-- .../client/api/AmqpTimestamp.cs | 85 +- .../client/api/AsyncDefaultBasicConsumer.cs | 303 +-- .../client/api/BasicGetResult.cs | 179 +- .../client/api/BasicProperties.cs | 395 ++-- .../client/api/BinaryTableValue.cs | 95 +- .../client/api/CachedString.cs | 93 +- .../client/api/ConnectionConfig.cs | 223 +-- .../client/api/ConnectionFactory.cs | 1067 +++++----- .../client/api/ConnectionFactoryBase.cs | 41 +- .../client/api/DefaultBasicConsumer.cs | 269 +-- .../client/api/DefaultEndpointResolver.cs | 23 +- .../client/api/DeliveryModes.cs | 25 +- .../client/api/ExchangeType.cs | 67 +- .../client/api/ExternalMechanism.cs | 17 +- .../client/api/ExternalMechanismFactory.cs | 31 +- .../RabbitMQ.Client/client/api/Headers.cs | 231 +-- .../RabbitMQ.Client/client/api/IAmqpHeader.cs | 19 +- .../client/api/IAmqpWriteable.cs | 33 +- .../client/api/IAsyncBasicConsumer.cs | 113 +- .../client/api/IAuthMechanism.cs | 17 +- .../client/api/IAuthMechanismFactory.cs | 23 +- .../client/api/IBasicConsumer.cs | 127 +- .../client/api/IBasicProperties.cs | 653 +++---- .../RabbitMQ.Client/client/api/IConnection.cs | 353 ++-- .../client/api/IConnectionExtensions.cs | 277 +-- .../client/api/IConnectionFactory.cs | 305 +-- .../client/api/IEndpointResolver.cs | 15 +- .../client/api/IEndpointResolverExtensions.cs | 41 +- projects/RabbitMQ.Client/client/api/IModel.cs | 799 ++++---- .../client/api/IModelExtensions.cs | 399 ++-- .../client/api/INetworkConnection.cs | 25 +- .../RabbitMQ.Client/client/api/IProtocol.cs | 53 +- .../client/api/IRecoverable.cs | 15 +- .../RabbitMQ.Client/client/api/ITcpClient.cs | 29 +- .../client/api/InternalConstants.cs | 11 +- .../client/api/PlainMechanism.cs | 11 +- .../client/api/PlainMechanismFactory.cs | 31 +- .../RabbitMQ.Client/client/api/Protocols.cs | 27 +- .../client/api/PublicationAddress.cs | 181 +- .../client/api/QueueDeclareOk.cs | 61 +- .../client/api/ReadonlyBasicProperties.cs | 155 +- .../client/api/ShutdownEventArgs.cs | 125 +- .../client/api/ShutdownInitiator.cs | 55 +- .../client/api/ShutdownReportEntry.cs | 47 +- .../RabbitMQ.Client/client/api/SslOption.cs | 239 +-- .../client/events/AsyncEventHandler.cs | 7 +- .../events/AsyncEventingBasicConsumer.cs | 135 +- .../client/events/BasicAckEventArgs.cs | 25 +- .../client/events/BasicDeliverEventArgs.cs | 89 +- .../client/events/BasicNackEventArgs.cs | 31 +- .../client/events/BasicReturnEventArgs.cs | 53 +- .../events/CallbackExceptionEventArgs.cs | 113 +- .../events/ConnectionBlockedEventArgs.cs | 27 +- .../ConnectionRecoveryErrorEventArgs.cs | 15 +- .../client/events/ConsumerEventArgs.cs | 27 +- ...onsumerTagChangedAfterRecoveryEventArgs.cs | 41 +- .../client/events/EventingBasicConsumer.cs | 113 +- .../client/events/FlowControlEventArgs.cs | 27 +- .../QueueNameChangedAfterRecoveryEventArgs.cs | 41 +- .../exceptions/AlreadyClosedException.cs | 23 +- .../AuthenticationFailureException.cs | 15 +- .../exceptions/BrokerUnreachableException.cs | 21 +- .../exceptions/ChannelAllocationException.cs | 57 +- .../exceptions/ConnectFailureException.cs | 15 +- .../exceptions/HardProtocolException.cs | 13 +- .../exceptions/MalformedFrameException.cs | 31 +- .../OperationInterruptedException.cs | 83 +- .../PacketNotRecognizedException.cs | 63 +- .../PossibleAuthenticationFailureException.cs | 21 +- .../client/exceptions/ProtocolException.cs | 41 +- .../ProtocolVersionMismatchException.cs | 59 +- .../exceptions/ProtocolViolationException.cs | 23 +- .../exceptions/RabbitMQClientException.cs | 35 +- .../client/exceptions/SyntaxErrorException.cs | 21 +- .../exceptions/TopologyRecoveryException.cs | 9 +- .../exceptions/UnexpectedFrameException.cs | 23 +- .../exceptions/UnexpectedMethodException.cs | 77 +- .../UnknownClassOrMethodException.cs | 51 +- .../exceptions/WireFormattingException.cs | 41 +- .../client/framing/BasicAck.cs | 51 +- .../client/framing/BasicCancel.cs | 53 +- .../client/framing/BasicCancelOk.cs | 19 +- .../client/framing/BasicConsume.cs | 77 +- .../client/framing/BasicConsumeOk.cs | 19 +- .../client/framing/BasicDeliver.cs | 35 +- .../client/framing/BasicGet.cs | 49 +- .../client/framing/BasicGetOk.cs | 35 +- .../client/framing/BasicMethodConstants.cs | 43 +- .../client/framing/BasicNack.cs | 53 +- .../client/framing/BasicPublish.cs | 117 +- .../client/framing/BasicQos.cs | 45 +- .../client/framing/BasicRecover.cs | 33 +- .../client/framing/BasicRecoverAsync.cs | 33 +- .../client/framing/BasicReject.cs | 39 +- .../client/framing/BasicReturn.cs | 31 +- .../client/framing/ChannelClose.cs | 69 +- .../client/framing/ChannelCloseOk.cs | 23 +- .../client/framing/ChannelFlow.cs | 19 +- .../client/framing/ChannelFlowOk.cs | 33 +- .../client/framing/ChannelMethodConstants.cs | 19 +- .../client/framing/ChannelOpen.cs | 29 +- .../client/framing/ClassConstants.cs | 21 +- .../client/framing/ConfirmMethodConstants.cs | 11 +- .../client/framing/ConfirmSelect.cs | 33 +- .../client/framing/ConnectionBlocked.cs | 19 +- .../client/framing/ConnectionClose.cs | 69 +- .../client/framing/ConnectionCloseOk.cs | 23 +- .../framing/ConnectionMethodConstants.cs | 35 +- .../client/framing/ConnectionOpen.cs | 49 +- .../client/framing/ConnectionSecure.cs | 19 +- .../client/framing/ConnectionSecureOk.cs | 37 +- .../client/framing/ConnectionStart.cs | 35 +- .../client/framing/ConnectionStartOk.cs | 61 +- .../client/framing/ConnectionTune.cs | 27 +- .../client/framing/ConnectionTuneOk.cs | 45 +- .../client/framing/ConnectionUpdateSecret.cs | 45 +- .../client/framing/Constants.cs | 103 +- .../client/framing/ExchangeBind.cs | 73 +- .../client/framing/ExchangeDeclare.cs | 81 +- .../client/framing/ExchangeDelete.cs | 53 +- .../client/framing/ExchangeMethodConstants.cs | 23 +- .../client/framing/ExchangeUnbind.cs | 73 +- .../client/framing/IAmqpMethod.cs | 15 +- .../RabbitMQ.Client/client/framing/Model.cs | 621 +++--- .../client/framing/Protocol.cs | 33 +- .../client/framing/ProtocolCommandId.cs | 135 +- .../client/framing/QueueBind.cs | 73 +- .../client/framing/QueueDeclare.cs | 73 +- .../client/framing/QueueDeclareOk.cs | 27 +- .../client/framing/QueueDelete.cs | 57 +- .../client/framing/QueueDeleteOk.cs | 19 +- .../client/framing/QueueMethodConstants.cs | 27 +- .../client/framing/QueuePurge.cs | 49 +- .../client/framing/QueuePurgeOk.cs | 19 +- .../client/framing/QueueUnbind.cs | 67 +- .../client/framing/TxCommit.cs | 23 +- .../client/framing/TxMethodConstants.cs | 19 +- .../client/framing/TxRollback.cs | 23 +- .../client/framing/TxSelect.cs | 23 +- .../client/impl/AmqpVersion.cs | 133 +- .../AutorecoveringConnection.Recording.cs | 271 +-- .../impl/AutorecoveringConnection.Recovery.cs | 407 ++-- .../client/impl/AutorecoveringConnection.cs | 297 +-- .../client/impl/AutorecoveringModel.cs | 603 +++--- .../client/impl/CommandAssembler.cs | 271 +-- .../client/impl/Connection.Commands.cs | 225 +-- .../client/impl/Connection.Heartbeat.cs | 195 +- .../client/impl/Connection.Receive.cs | 253 +-- .../RabbitMQ.Client/client/impl/Connection.cs | 599 +++--- .../client/impl/ConnectionSecureOrTune.cs | 33 +- .../client/impl/ConnectionStartDetails.cs | 17 +- .../AsyncConsumerDispatcher.cs | 61 +- .../ConsumerDispatching/ConsumerDispatcher.cs | 79 +- .../ConsumerDispatcherBase.cs | 85 +- .../ConsumerDispatcherChannelBase.cs | 241 +-- .../ConsumerDispatching/FallbackConsumer.cs | 123 +- .../IConsumerDispatcher.cs | 43 +- .../client/impl/EmptyBasicProperty.cs | 89 +- .../client/impl/EventingWrapper.cs | 193 +- projects/RabbitMQ.Client/client/impl/Frame.cs | 495 ++--- .../client/impl/IFrameHandler.cs | 39 +- .../client/impl/IRpcContinuation.cs | 11 +- .../RabbitMQ.Client/client/impl/ISession.cs | 75 +- .../client/impl/IncomingCommand.cs | 83 +- .../client/impl/MainSession.cs | 109 +- .../RabbitMQ.Client/client/impl/ModelBase.cs | 1727 +++++++++-------- .../client/impl/ProtocolBase.cs | 73 +- .../client/impl/RecordedBinding.cs | 119 +- .../client/impl/RecordedConsumer.cs | 65 +- .../client/impl/RecordedExchange.cs | 53 +- .../client/impl/RecordedQueue.cs | 79 +- .../client/impl/RecoveryAwareModel.cs | 77 +- .../client/impl/RpcContinuationQueue.cs | 129 +- .../RabbitMQ.Client/client/impl/Session.cs | 33 +- .../client/impl/SessionBase.cs | 167 +- .../client/impl/SessionManager.cs | 85 +- .../client/impl/ShutdownContinuation.cs | 59 +- .../impl/SimpleBlockingRpcContinuation.cs | 61 +- .../client/impl/SocketFrameHandler.cs | 483 +++-- .../RabbitMQ.Client/client/impl/SslHelper.cs | 117 +- .../client/impl/TcpClientAdapter.cs | 145 +- .../client/impl/TcpClientAdapterHelper.cs | 17 +- .../client/impl/WireFormatting.Read.cs | 439 ++--- .../client/impl/WireFormatting.Write.cs | 701 +++---- .../client/impl/WireFormatting.cs | 57 +- .../RabbitMQ.Client/client/logging/ESLog.cs | 57 +- .../RabbitMqClientEventSource.Counters.cs | 135 +- .../logging/RabbitMqClientEventSource.cs | 85 +- .../client/logging/RabbitMqExceptionDetail.cs | 55 +- projects/RabbitMQ.Client/util/BlockingCell.cs | 95 +- projects/RabbitMQ.Client/util/Either.cs | 65 +- projects/RabbitMQ.Client/util/IntAllocator.cs | 261 +-- .../util/NetworkOrderDeserializer.cs | 101 +- .../util/NetworkOrderSerializer.cs | 103 +- .../RabbitMQ.Client/util/TypeExtensions.cs | 103 +- 198 files changed, 11710 insertions(+), 11514 deletions(-) diff --git a/projects/RabbitMQ.Client/FrameworkExtension/DictionaryExtension.cs b/projects/RabbitMQ.Client/FrameworkExtension/DictionaryExtension.cs index 42cb2e49a5..2fcbaa2aa6 100644 --- a/projects/RabbitMQ.Client/FrameworkExtension/DictionaryExtension.cs +++ b/projects/RabbitMQ.Client/FrameworkExtension/DictionaryExtension.cs @@ -1,13 +1,15 @@ using System.Collections.Generic; -namespace RabbitMQ; +namespace RabbitMQ +{ #nullable enable #if NETSTANDARD -internal static class DictionaryExtension -{ - public static bool Remove(this Dictionary dictionary, TKey key, out TValue value) + internal static class DictionaryExtension { - return dictionary.TryGetValue(key, out value) && dictionary.Remove(key); + public static bool Remove(this Dictionary dictionary, TKey key, out TValue value) + { + return dictionary.TryGetValue(key, out value) && dictionary.Remove(key); + } } -} #endif +} diff --git a/projects/RabbitMQ.Client/FrameworkExtension/StringExtension.cs b/projects/RabbitMQ.Client/FrameworkExtension/StringExtension.cs index ce7514056f..252f86ca58 100644 --- a/projects/RabbitMQ.Client/FrameworkExtension/StringExtension.cs +++ b/projects/RabbitMQ.Client/FrameworkExtension/StringExtension.cs @@ -1,13 +1,15 @@ using System; -namespace RabbitMQ; +namespace RabbitMQ +{ #nullable enable #if NETSTANDARD -internal static class StringExtension -{ - public static bool Contains(this string toSearch, string value, StringComparison comparisonType) + internal static class StringExtension { - return toSearch.IndexOf(value, comparisonType) > 0; + public static bool Contains(this string toSearch, string value, StringComparison comparisonType) + { + return toSearch.IndexOf(value, comparisonType) > 0; + } } -} #endif +} diff --git a/projects/RabbitMQ.Client/client/api/AmqpTcpEndpoint.cs b/projects/RabbitMQ.Client/client/api/AmqpTcpEndpoint.cs index c993393b65..42fd9f7b04 100644 --- a/projects/RabbitMQ.Client/client/api/AmqpTcpEndpoint.cs +++ b/projects/RabbitMQ.Client/client/api/AmqpTcpEndpoint.cs @@ -33,247 +33,248 @@ using System.Collections.Generic; using System.Text.RegularExpressions; -namespace RabbitMQ.Client; - -/// -/// Represents a TCP-addressable AMQP peer: a host name and port number. -/// -/// -/// -/// Some of the constructors take, as a convenience, a -/// instance representing an AMQP server address. The use of Uri -/// here is not standardised - Uri is simply a convenient -/// container for internet-address-like components. In particular, -/// the Uri "Scheme" property is ignored: only the "Host" and -/// "Port" properties are extracted. -/// -/// -public class AmqpTcpEndpoint// : ICloneable +namespace RabbitMQ.Client { /// - /// Default Amqp ssl port. + /// Represents a TCP-addressable AMQP peer: a host name and port number. /// - public const int DefaultAmqpSslPort = 5671; + /// + /// + /// Some of the constructors take, as a convenience, a + /// instance representing an AMQP server address. The use of Uri + /// here is not standardised - Uri is simply a convenient + /// container for internet-address-like components. In particular, + /// the Uri "Scheme" property is ignored: only the "Host" and + /// "Port" properties are extracted. + /// + /// + public class AmqpTcpEndpoint// : ICloneable + { + /// + /// Default Amqp ssl port. + /// + public const int DefaultAmqpSslPort = 5671; - /// - /// Indicates that the default port for the protocol should be used. - /// - public const int UseDefaultPort = -1; + /// + /// Indicates that the default port for the protocol should be used. + /// + public const int UseDefaultPort = -1; - private int _port; + private int _port; - /// - /// Creates a new instance of the . - /// - /// Hostname. - /// Port number. If the port number is -1, the default port number will be used. - /// Ssl option. - public AmqpTcpEndpoint(string hostName, int portOrMinusOne, SslOption ssl) - { - HostName = hostName; - _port = portOrMinusOne; - Ssl = ssl; - } + /// + /// Creates a new instance of the . + /// + /// Hostname. + /// Port number. If the port number is -1, the default port number will be used. + /// Ssl option. + public AmqpTcpEndpoint(string hostName, int portOrMinusOne, SslOption ssl) + { + HostName = hostName; + _port = portOrMinusOne; + Ssl = ssl; + } - /// - /// Creates a new instance of the . - /// - /// Hostname. - /// Port number. If the port number is -1, the default port number will be used. - public AmqpTcpEndpoint(string hostName, int portOrMinusOne = -1) : - this(hostName, portOrMinusOne, new SslOption()) - { - } + /// + /// Creates a new instance of the . + /// + /// Hostname. + /// Port number. If the port number is -1, the default port number will be used. + public AmqpTcpEndpoint(string hostName, int portOrMinusOne = -1) : + this(hostName, portOrMinusOne, new SslOption()) + { + } - /// - /// Construct an AmqpTcpEndpoint with "localhost" as the hostname, and using the default port. - /// - public AmqpTcpEndpoint() : this("localhost") - { - } + /// + /// Construct an AmqpTcpEndpoint with "localhost" as the hostname, and using the default port. + /// + public AmqpTcpEndpoint() : this("localhost") + { + } - /// - /// Creates a new instance of the with the given Uri and ssl options. - /// - /// - /// Please see the class overview documentation for information about the Uri format in use. - /// - public AmqpTcpEndpoint(Uri uri, SslOption ssl) : this(uri.Host, uri.Port, ssl) - { - } + /// + /// Creates a new instance of the with the given Uri and ssl options. + /// + /// + /// Please see the class overview documentation for information about the Uri format in use. + /// + public AmqpTcpEndpoint(Uri uri, SslOption ssl) : this(uri.Host, uri.Port, ssl) + { + } - /// - /// Creates a new instance of the with the given Uri. - /// - /// - /// Please see the class overview documentation for information about the Uri format in use. - /// - public AmqpTcpEndpoint(Uri uri) : this(uri.Host, uri.Port) - { - } + /// + /// Creates a new instance of the with the given Uri. + /// + /// + /// Please see the class overview documentation for information about the Uri format in use. + /// + public AmqpTcpEndpoint(Uri uri) : this(uri.Host, uri.Port) + { + } - /// - /// Clones the endpoint. - /// - /// A copy with the same hostname, port, and TLS settings - public object Clone() - { - return new AmqpTcpEndpoint(HostName, _port, Ssl); - } + /// + /// Clones the endpoint. + /// + /// A copy with the same hostname, port, and TLS settings + public object Clone() + { + return new AmqpTcpEndpoint(HostName, _port, Ssl); + } - /// - /// Clones the endpoint using the provided hostname. - /// - /// Hostname to use - /// A copy with the provided hostname and port/TLS settings of this endpoint - public AmqpTcpEndpoint CloneWithHostname(string hostname) - { - return new AmqpTcpEndpoint(hostname, _port, Ssl); - } + /// + /// Clones the endpoint using the provided hostname. + /// + /// Hostname to use + /// A copy with the provided hostname and port/TLS settings of this endpoint + public AmqpTcpEndpoint CloneWithHostname(string hostname) + { + return new AmqpTcpEndpoint(hostname, _port, Ssl); + } - /// - /// Retrieve or set the hostname of this . - /// - public string HostName { get; set; } + /// + /// Retrieve or set the hostname of this . + /// + public string HostName { get; set; } - /// Retrieve or set the port number of this - ///AmqpTcpEndpoint. A port number of -1 causes the default - ///port number. - public int Port - { - get + /// Retrieve or set the port number of this + ///AmqpTcpEndpoint. A port number of -1 causes the default + ///port number. + public int Port { - if (_port != UseDefaultPort) - { - return _port; - } - if (Ssl.Enabled) + get { - return DefaultAmqpSslPort; + if (_port != UseDefaultPort) + { + return _port; + } + if (Ssl.Enabled) + { + return DefaultAmqpSslPort; + } + return Protocol.DefaultPort; } - return Protocol.DefaultPort; + set { _port = value; } } - set { _port = value; } - } - /// - /// Retrieve IProtocol of this . - /// - public IProtocol Protocol - { - get { return Protocols.DefaultProtocol; } - } + /// + /// Retrieve IProtocol of this . + /// + public IProtocol Protocol + { + get { return Protocols.DefaultProtocol; } + } - /// - /// Used to force the address family of the endpoint. - /// Use to force to IPv4. - /// Use to force to IPv6. - /// Or use to attempt both IPv6 and IPv4. - /// - public System.Net.Sockets.AddressFamily AddressFamily { get; set; } = ConnectionFactory.DefaultAddressFamily; + /// + /// Used to force the address family of the endpoint. + /// Use to force to IPv4. + /// Use to force to IPv6. + /// Or use to attempt both IPv6 and IPv4. + /// + public System.Net.Sockets.AddressFamily AddressFamily { get; set; } = ConnectionFactory.DefaultAddressFamily; - /// - /// Retrieve the TLS options for this AmqpTcpEndpoint. If not set, null is returned. - /// - public SslOption Ssl { get; set; } + /// + /// Retrieve the TLS options for this AmqpTcpEndpoint. If not set, null is returned. + /// + public SslOption Ssl { get; set; } - /// - /// Construct an instance from a protocol and an address in "hostname:port" format. - /// - /// - /// If the address string passed in contains ":", it is split - /// into a hostname and a port-number part. Otherwise, the - /// entire string is used as the hostname, and the port-number - /// is set to -1 (meaning the default number for the protocol - /// variant specified). - /// Hostnames provided as IPv6 must appear in square brackets ([]). - /// - public static AmqpTcpEndpoint Parse(string address) - { - Match match = Regex.Match(address, @"^\s*\[([%:0-9A-Fa-f]+)\](:(.*))?\s*$"); - string port; - int portNumber; - if (match.Success) + /// + /// Construct an instance from a protocol and an address in "hostname:port" format. + /// + /// + /// If the address string passed in contains ":", it is split + /// into a hostname and a port-number part. Otherwise, the + /// entire string is used as the hostname, and the port-number + /// is set to -1 (meaning the default number for the protocol + /// variant specified). + /// Hostnames provided as IPv6 must appear in square brackets ([]). + /// + public static AmqpTcpEndpoint Parse(string address) { - GroupCollection groups = match.Groups; - portNumber = -1; - if (groups[2].Success) + Match match = Regex.Match(address, @"^\s*\[([%:0-9A-Fa-f]+)\](:(.*))?\s*$"); + string port; + int portNumber; + if (match.Success) { - port = groups[3].Value; - portNumber = (port.Length == 0) ? -1 : int.Parse(port); + GroupCollection groups = match.Groups; + portNumber = -1; + if (groups[2].Success) + { + port = groups[3].Value; + portNumber = (port.Length == 0) ? -1 : int.Parse(port); + } + return new AmqpTcpEndpoint(match.Groups[1].Value, portNumber); } - return new AmqpTcpEndpoint(match.Groups[1].Value, portNumber); - } - int index = address.LastIndexOf(':'); - if (index == -1) - { - return new AmqpTcpEndpoint(address); + int index = address.LastIndexOf(':'); + if (index == -1) + { + return new AmqpTcpEndpoint(address); + } + port = address.Substring(index + 1).Trim(); + portNumber = (port.Length == 0) ? -1 : int.Parse(port); + return new AmqpTcpEndpoint(address.Substring(0, index), portNumber); } - port = address.Substring(index + 1).Trim(); - portNumber = (port.Length == 0) ? -1 : int.Parse(port); - return new AmqpTcpEndpoint(address.Substring(0, index), portNumber); - } - /// - /// Splits the passed-in string on ",", and passes the substrings to . - /// - /// - /// Accepts a string of the form "hostname:port, - /// hostname:port, ...", where the ":port" pieces are - /// optional, and returns a corresponding array of s. - /// - public static AmqpTcpEndpoint[] ParseMultiple(string addresses) - { - string[] partsArr = addresses.Split(','); - var results = new List(); - foreach (string partRaw in partsArr) + /// + /// Splits the passed-in string on ",", and passes the substrings to . + /// + /// + /// Accepts a string of the form "hostname:port, + /// hostname:port, ...", where the ":port" pieces are + /// optional, and returns a corresponding array of s. + /// + public static AmqpTcpEndpoint[] ParseMultiple(string addresses) { - string part = partRaw.Trim(); - if (part.Length > 0) + string[] partsArr = addresses.Split(','); + var results = new List(); + foreach (string partRaw in partsArr) { - results.Add(Parse(part)); + string part = partRaw.Trim(); + if (part.Length > 0) + { + results.Add(Parse(part)); + } } + return results.ToArray(); } - return results.ToArray(); - } - /// - /// Compares this instance by value (protocol, hostname, port) against another instance. - /// - public override bool Equals(object obj) - { - if (!(obj is AmqpTcpEndpoint other)) + /// + /// Compares this instance by value (protocol, hostname, port) against another instance. + /// + public override bool Equals(object obj) { - return false; + if (!(obj is AmqpTcpEndpoint other)) + { + return false; + } + if (other.HostName != HostName) + { + return false; + } + if (other.Port != Port) + { + return false; + } + return true; } - if (other.HostName != HostName) + + /// + /// Implementation of hash code depending on protocol, hostname and port, + /// to line up with the implementation of . + /// + public override int GetHashCode() { - return false; + return HostName.GetHashCode() ^ Port; } - if (other.Port != Port) + + /// + /// Returns a URI-like string of the form amqp-PROTOCOL://HOSTNAME:PORTNUMBER. + /// + /// + /// This method is intended mainly for debugging and logging use. + /// + public override string ToString() { - return false; + return $"{(Ssl.Enabled ? "amqps" : "amqp")}://{HostName}:{Port}"; } - return true; - } - - /// - /// Implementation of hash code depending on protocol, hostname and port, - /// to line up with the implementation of . - /// - public override int GetHashCode() - { - return HostName.GetHashCode() ^ Port; - } - - /// - /// Returns a URI-like string of the form amqp-PROTOCOL://HOSTNAME:PORTNUMBER. - /// - /// - /// This method is intended mainly for debugging and logging use. - /// - public override string ToString() - { - return $"{(Ssl.Enabled ? "amqps" : "amqp")}://{HostName}:{Port}"; } } diff --git a/projects/RabbitMQ.Client/client/api/AmqpTimestamp.cs b/projects/RabbitMQ.Client/client/api/AmqpTimestamp.cs index 42a7c5f28c..78cb0f5381 100644 --- a/projects/RabbitMQ.Client/client/api/AmqpTimestamp.cs +++ b/projects/RabbitMQ.Client/client/api/AmqpTimestamp.cs @@ -31,57 +31,58 @@ using System; -namespace RabbitMQ.Client; - -// time representations in mainstream languages: the horror, the horror -// see in particular the difference between .NET 1.x and .NET 2.0's versions of DateTime - -/// -/// Structure holding an AMQP timestamp, a posix 64-bit time_t. -/// -/// -/// When converting between an AmqpTimestamp and a System.DateTime, -/// be aware of the effect of your local timezone. In particular, -/// different versions of the .NET framework assume different -/// defaults. -/// -/// -/// We have chosen a signed 64-bit time_t here, since the AMQP -/// specification through versions 0-9 is silent on whether -/// timestamps are signed or unsigned. -/// -/// -public readonly struct AmqpTimestamp : IEquatable +namespace RabbitMQ.Client { + // time representations in mainstream languages: the horror, the horror + // see in particular the difference between .NET 1.x and .NET 2.0's versions of DateTime + /// - /// Construct an . - /// - /// Unix time. - public AmqpTimestamp(long unixTime) : this() + /// Structure holding an AMQP timestamp, a posix 64-bit time_t. + /// + /// + /// When converting between an AmqpTimestamp and a System.DateTime, + /// be aware of the effect of your local timezone. In particular, + /// different versions of the .NET framework assume different + /// defaults. + /// + /// + /// We have chosen a signed 64-bit time_t here, since the AMQP + /// specification through versions 0-9 is silent on whether + /// timestamps are signed or unsigned. + /// + /// + public readonly struct AmqpTimestamp : IEquatable { - UnixTime = unixTime; - } + /// + /// Construct an . + /// + /// Unix time. + public AmqpTimestamp(long unixTime) : this() + { + UnixTime = unixTime; + } - /// - /// Unix time. - /// - public long UnixTime { get; } + /// + /// Unix time. + /// + public long UnixTime { get; } - public bool Equals(AmqpTimestamp other) => UnixTime == other.UnixTime; + public bool Equals(AmqpTimestamp other) => UnixTime == other.UnixTime; - public override bool Equals(object obj) => obj is AmqpTimestamp other && Equals(other); + public override bool Equals(object obj) => obj is AmqpTimestamp other && Equals(other); - public override int GetHashCode() => UnixTime.GetHashCode(); + public override int GetHashCode() => UnixTime.GetHashCode(); - public static bool operator ==(AmqpTimestamp left, AmqpTimestamp right) => left.Equals(right); + public static bool operator ==(AmqpTimestamp left, AmqpTimestamp right) => left.Equals(right); - public static bool operator !=(AmqpTimestamp left, AmqpTimestamp right) => !left.Equals(right); + public static bool operator !=(AmqpTimestamp left, AmqpTimestamp right) => !left.Equals(right); - /// - /// Provides a debugger-friendly display. - /// - public override string ToString() - { - return $"((time_t){UnixTime})"; + /// + /// Provides a debugger-friendly display. + /// + public override string ToString() + { + return $"((time_t){UnixTime})"; + } } } diff --git a/projects/RabbitMQ.Client/client/api/AsyncDefaultBasicConsumer.cs b/projects/RabbitMQ.Client/client/api/AsyncDefaultBasicConsumer.cs index 4d77c4df1a..fdab6e02dd 100644 --- a/projects/RabbitMQ.Client/client/api/AsyncDefaultBasicConsumer.cs +++ b/projects/RabbitMQ.Client/client/api/AsyncDefaultBasicConsumer.cs @@ -5,178 +5,179 @@ using RabbitMQ.Client.Events; using RabbitMQ.Client.Impl; -namespace RabbitMQ.Client; - -public class AsyncDefaultBasicConsumer : IBasicConsumer, IAsyncBasicConsumer +namespace RabbitMQ.Client { - private readonly HashSet _consumerTags = new HashSet(); - - /// - /// Creates a new instance of an . - /// - public AsyncDefaultBasicConsumer() + public class AsyncDefaultBasicConsumer : IBasicConsumer, IAsyncBasicConsumer { - } + private readonly HashSet _consumerTags = new HashSet(); - /// - /// Constructor which sets the Model property to the given value. - /// - /// Common AMQP model. - public AsyncDefaultBasicConsumer(IModel model) - { - Model = model; - } + /// + /// Creates a new instance of an . + /// + public AsyncDefaultBasicConsumer() + { + } - /// - /// Retrieve the consumer tags this consumer is registered as; to be used when discussing this consumer - /// with the server, for instance with . - /// - public string[] ConsumerTags - { - get + /// + /// Constructor which sets the Model property to the given value. + /// + /// Common AMQP model. + public AsyncDefaultBasicConsumer(IModel model) { - return _consumerTags.ToArray(); + Model = model; } - } - /// - /// Returns true while the consumer is registered and expecting deliveries from the broker. - /// - public bool IsRunning { get; protected set; } - - /// - /// If our shuts down, this property will contain a description of the reason for the - /// shutdown. Otherwise it will contain null. See . - /// - public ShutdownEventArgs ShutdownReason { get; protected set; } - - /// - /// Signalled when the consumer gets cancelled. - /// - public event AsyncEventHandler ConsumerCancelled - { - add => _consumerCancelledWrapper.AddHandler(value); - remove => _consumerCancelledWrapper.RemoveHandler(value); - } - private AsyncEventingWrapper _consumerCancelledWrapper; - - /// - /// Retrieve the this consumer is associated with, - /// for use in acknowledging received messages, for instance. - /// - public IModel Model { get; set; } - - /// - /// Called when the consumer is cancelled for reasons other than by a basicCancel: - /// e.g. the queue has been deleted (either by this channel or by any other channel). - /// See for notification of consumer cancellation due to basicCancel - /// - /// Consumer tag this consumer is registered. - public virtual Task HandleBasicCancel(string consumerTag) - { - return OnCancel(consumerTag); - } + /// + /// Retrieve the consumer tags this consumer is registered as; to be used when discussing this consumer + /// with the server, for instance with . + /// + public string[] ConsumerTags + { + get + { + return _consumerTags.ToArray(); + } + } - /// - /// Called upon successful deregistration of the consumer from the broker. - /// - /// Consumer tag this consumer is registered. - public virtual Task HandleBasicCancelOk(string consumerTag) - { - return OnCancel(consumerTag); - } + /// + /// Returns true while the consumer is registered and expecting deliveries from the broker. + /// + public bool IsRunning { get; protected set; } + + /// + /// If our shuts down, this property will contain a description of the reason for the + /// shutdown. Otherwise it will contain null. See . + /// + public ShutdownEventArgs ShutdownReason { get; protected set; } + + /// + /// Signalled when the consumer gets cancelled. + /// + public event AsyncEventHandler ConsumerCancelled + { + add => _consumerCancelledWrapper.AddHandler(value); + remove => _consumerCancelledWrapper.RemoveHandler(value); + } + private AsyncEventingWrapper _consumerCancelledWrapper; + + /// + /// Retrieve the this consumer is associated with, + /// for use in acknowledging received messages, for instance. + /// + public IModel Model { get; set; } + + /// + /// Called when the consumer is cancelled for reasons other than by a basicCancel: + /// e.g. the queue has been deleted (either by this channel or by any other channel). + /// See for notification of consumer cancellation due to basicCancel + /// + /// Consumer tag this consumer is registered. + public virtual Task HandleBasicCancel(string consumerTag) + { + return OnCancel(consumerTag); + } - /// - /// Called upon successful registration of the consumer with the broker. - /// - /// Consumer tag this consumer is registered. - public virtual Task HandleBasicConsumeOk(string consumerTag) - { - _consumerTags.Add(consumerTag); - IsRunning = true; - return Task.CompletedTask; - } + /// + /// Called upon successful deregistration of the consumer from the broker. + /// + /// Consumer tag this consumer is registered. + public virtual Task HandleBasicCancelOk(string consumerTag) + { + return OnCancel(consumerTag); + } - /// - /// Called each time a message is delivered for this consumer. - /// - /// - /// This is a no-op implementation. It will not acknowledge deliveries via - /// if consuming in automatic acknowledgement mode. - /// Subclasses must copy or fully use delivery body before returning. - /// Accessing the body at a later point is unsafe as its memory can - /// be already released. - /// - public virtual Task HandleBasicDeliver(string consumerTag, - ulong deliveryTag, - bool redelivered, - string exchange, - string routingKey, - in ReadOnlyBasicProperties properties, - ReadOnlyMemory body) - { - // Nothing to do here. - return Task.CompletedTask; - } + /// + /// Called upon successful registration of the consumer with the broker. + /// + /// Consumer tag this consumer is registered. + public virtual Task HandleBasicConsumeOk(string consumerTag) + { + _consumerTags.Add(consumerTag); + IsRunning = true; + return Task.CompletedTask; + } - /// - /// Called when the model (channel) this consumer was registered on terminates. - /// - /// A channel this consumer was registered on. - /// Shutdown context. - public virtual Task HandleModelShutdown(object model, ShutdownEventArgs reason) - { - ShutdownReason = reason; - return OnCancel(_consumerTags.ToArray()); - } + /// + /// Called each time a message is delivered for this consumer. + /// + /// + /// This is a no-op implementation. It will not acknowledge deliveries via + /// if consuming in automatic acknowledgement mode. + /// Subclasses must copy or fully use delivery body before returning. + /// Accessing the body at a later point is unsafe as its memory can + /// be already released. + /// + public virtual Task HandleBasicDeliver(string consumerTag, + ulong deliveryTag, + bool redelivered, + string exchange, + string routingKey, + in ReadOnlyBasicProperties properties, + ReadOnlyMemory body) + { + // Nothing to do here. + return Task.CompletedTask; + } - /// - /// Default implementation - overridable in subclasses. - /// The set of consumer tags that where cancelled - /// - /// This default implementation simply sets the property to false, and takes no further action. - /// - public virtual async Task OnCancel(params string[] consumerTags) - { - IsRunning = false; - if (!_consumerCancelledWrapper.IsEmpty) + /// + /// Called when the model (channel) this consumer was registered on terminates. + /// + /// A channel this consumer was registered on. + /// Shutdown context. + public virtual Task HandleModelShutdown(object model, ShutdownEventArgs reason) { - await _consumerCancelledWrapper.InvokeAsync(this, new ConsumerEventArgs(consumerTags)).ConfigureAwait(false); + ShutdownReason = reason; + return OnCancel(_consumerTags.ToArray()); } - foreach (string consumerTag in consumerTags) + + /// + /// Default implementation - overridable in subclasses. + /// The set of consumer tags that where cancelled + /// + /// This default implementation simply sets the property to false, and takes no further action. + /// + public virtual async Task OnCancel(params string[] consumerTags) { - _consumerTags.Remove(consumerTag); + IsRunning = false; + if (!_consumerCancelledWrapper.IsEmpty) + { + await _consumerCancelledWrapper.InvokeAsync(this, new ConsumerEventArgs(consumerTags)).ConfigureAwait(false); + } + foreach (string consumerTag in consumerTags) + { + _consumerTags.Remove(consumerTag); + } } - } - event EventHandler IBasicConsumer.ConsumerCancelled - { - add { throw new InvalidOperationException("Should never be called. Enable 'DispatchConsumersAsync'."); } - remove { throw new InvalidOperationException("Should never be called. Enable 'DispatchConsumersAsync'."); } - } + event EventHandler IBasicConsumer.ConsumerCancelled + { + add { throw new InvalidOperationException("Should never be called. Enable 'DispatchConsumersAsync'."); } + remove { throw new InvalidOperationException("Should never be called. Enable 'DispatchConsumersAsync'."); } + } - void IBasicConsumer.HandleBasicCancelOk(string consumerTag) - { - throw new InvalidOperationException("Should never be called. Enable 'DispatchConsumersAsync'."); - } + void IBasicConsumer.HandleBasicCancelOk(string consumerTag) + { + throw new InvalidOperationException("Should never be called. Enable 'DispatchConsumersAsync'."); + } - void IBasicConsumer.HandleBasicConsumeOk(string consumerTag) - { - throw new InvalidOperationException("Should never be called. Enable 'DispatchConsumersAsync'."); - } + void IBasicConsumer.HandleBasicConsumeOk(string consumerTag) + { + throw new InvalidOperationException("Should never be called. Enable 'DispatchConsumersAsync'."); + } - void IBasicConsumer.HandleBasicDeliver(string consumerTag, ulong deliveryTag, bool redelivered, string exchange, string routingKey, in ReadOnlyBasicProperties properties, ReadOnlyMemory body) - { - throw new InvalidOperationException("Should never be called. Enable 'DispatchConsumersAsync'."); - } + void IBasicConsumer.HandleBasicDeliver(string consumerTag, ulong deliveryTag, bool redelivered, string exchange, string routingKey, in ReadOnlyBasicProperties properties, ReadOnlyMemory body) + { + throw new InvalidOperationException("Should never be called. Enable 'DispatchConsumersAsync'."); + } - void IBasicConsumer.HandleModelShutdown(object model, ShutdownEventArgs reason) - { - throw new InvalidOperationException("Should never be called. Enable 'DispatchConsumersAsync'."); - } + void IBasicConsumer.HandleModelShutdown(object model, ShutdownEventArgs reason) + { + throw new InvalidOperationException("Should never be called. Enable 'DispatchConsumersAsync'."); + } - void IBasicConsumer.HandleBasicCancel(string consumerTag) - { - throw new InvalidOperationException("Should never be called. Enable 'DispatchConsumersAsync'."); + void IBasicConsumer.HandleBasicCancel(string consumerTag) + { + throw new InvalidOperationException("Should never be called. Enable 'DispatchConsumersAsync'."); + } } } diff --git a/projects/RabbitMQ.Client/client/api/BasicGetResult.cs b/projects/RabbitMQ.Client/client/api/BasicGetResult.cs index 59f8c7de09..fc79fa6f06 100644 --- a/projects/RabbitMQ.Client/client/api/BasicGetResult.cs +++ b/projects/RabbitMQ.Client/client/api/BasicGetResult.cs @@ -32,107 +32,108 @@ using System; using System.Buffers; -namespace RabbitMQ.Client; - -/// Represents Basic.GetOk responses from the server. -/// -/// Basic.Get either returns an instance of this class, or null if a Basic.GetEmpty was received. -/// -public sealed class BasicGetResult : IDisposable +namespace RabbitMQ.Client { - private readonly byte[] _rentedArray; - - /// - /// Sets the new instance's properties from the arguments passed in. - /// - /// Delivery tag for the message. - /// Redelivered flag for the message - /// The exchange this message was published to. - /// Routing key with which the message was published. - /// The number of messages pending on the queue, excluding the message being delivered. - /// The Basic-class content header properties for the message. - /// The body - public BasicGetResult(ulong deliveryTag, bool redelivered, string exchange, string routingKey, - uint messageCount, in ReadOnlyBasicProperties basicProperties, ReadOnlyMemory body) + /// Represents Basic.GetOk responses from the server. + /// + /// Basic.Get either returns an instance of this class, or null if a Basic.GetEmpty was received. + /// + public sealed class BasicGetResult : IDisposable { - DeliveryTag = deliveryTag; - Redelivered = redelivered; - Exchange = exchange; - RoutingKey = routingKey; - MessageCount = messageCount; - BasicProperties = basicProperties; - Body = body; - } + private readonly byte[] _rentedArray; - /// - /// Sets the new instance's properties from the arguments passed in. - /// - /// Delivery tag for the message. - /// Redelivered flag for the message - /// The exchange this message was published to. - /// Routing key with which the message was published. - /// The number of messages pending on the queue, excluding the message being delivered. - /// The Basic-class content header properties for the message. - /// The body - /// The rented array which body is part of. - public BasicGetResult(ulong deliveryTag, bool redelivered, string exchange, string routingKey, - uint messageCount, in ReadOnlyBasicProperties basicProperties, ReadOnlyMemory body, byte[] rentedArray) - { - DeliveryTag = deliveryTag; - Redelivered = redelivered; - Exchange = exchange; - RoutingKey = routingKey; - MessageCount = messageCount; - BasicProperties = basicProperties; - Body = body; - _rentedArray = rentedArray; - } + /// + /// Sets the new instance's properties from the arguments passed in. + /// + /// Delivery tag for the message. + /// Redelivered flag for the message + /// The exchange this message was published to. + /// Routing key with which the message was published. + /// The number of messages pending on the queue, excluding the message being delivered. + /// The Basic-class content header properties for the message. + /// The body + public BasicGetResult(ulong deliveryTag, bool redelivered, string exchange, string routingKey, + uint messageCount, in ReadOnlyBasicProperties basicProperties, ReadOnlyMemory body) + { + DeliveryTag = deliveryTag; + Redelivered = redelivered; + Exchange = exchange; + RoutingKey = routingKey; + MessageCount = messageCount; + BasicProperties = basicProperties; + Body = body; + } - /// - /// Retrieves the Basic-class content header properties for this message. - /// - public ReadOnlyBasicProperties BasicProperties { get; } + /// + /// Sets the new instance's properties from the arguments passed in. + /// + /// Delivery tag for the message. + /// Redelivered flag for the message + /// The exchange this message was published to. + /// Routing key with which the message was published. + /// The number of messages pending on the queue, excluding the message being delivered. + /// The Basic-class content header properties for the message. + /// The body + /// The rented array which body is part of. + public BasicGetResult(ulong deliveryTag, bool redelivered, string exchange, string routingKey, + uint messageCount, in ReadOnlyBasicProperties basicProperties, ReadOnlyMemory body, byte[] rentedArray) + { + DeliveryTag = deliveryTag; + Redelivered = redelivered; + Exchange = exchange; + RoutingKey = routingKey; + MessageCount = messageCount; + BasicProperties = basicProperties; + Body = body; + _rentedArray = rentedArray; + } - /// - /// Retrieves the body of this message. - /// - public ReadOnlyMemory Body { get; } + /// + /// Retrieves the Basic-class content header properties for this message. + /// + public ReadOnlyBasicProperties BasicProperties { get; } - /// - /// Retrieve the delivery tag for this message. See also . - /// - public ulong DeliveryTag { get; } + /// + /// Retrieves the body of this message. + /// + public ReadOnlyMemory Body { get; } - /// - /// Retrieve the exchange this message was published to. - /// - public string Exchange { get; } + /// + /// Retrieve the delivery tag for this message. See also . + /// + public ulong DeliveryTag { get; } - /// - /// Retrieve the number of messages pending on the queue, excluding the message being delivered. - /// - /// - /// Note that this figure is indicative, not reliable, and can - /// change arbitrarily as messages are added to the queue and removed by other clients. - /// - public uint MessageCount { get; } + /// + /// Retrieve the exchange this message was published to. + /// + public string Exchange { get; } - /// - /// Retrieve the redelivered flag for this message. - /// - public bool Redelivered { get; } + /// + /// Retrieve the number of messages pending on the queue, excluding the message being delivered. + /// + /// + /// Note that this figure is indicative, not reliable, and can + /// change arbitrarily as messages are added to the queue and removed by other clients. + /// + public uint MessageCount { get; } - /// - /// Retrieve the routing key with which this message was published. - /// - public string RoutingKey { get; } + /// + /// Retrieve the redelivered flag for this message. + /// + public bool Redelivered { get; } - /// - public void Dispose() - { - if (_rentedArray != null) + /// + /// Retrieve the routing key with which this message was published. + /// + public string RoutingKey { get; } + + /// + public void Dispose() { - ArrayPool.Shared.Return(_rentedArray); + if (_rentedArray != null) + { + ArrayPool.Shared.Return(_rentedArray); + } } } } diff --git a/projects/RabbitMQ.Client/client/api/BasicProperties.cs b/projects/RabbitMQ.Client/client/api/BasicProperties.cs index 7c8c477924..9133b8b8be 100644 --- a/projects/RabbitMQ.Client/client/api/BasicProperties.cs +++ b/projects/RabbitMQ.Client/client/api/BasicProperties.cs @@ -34,236 +34,237 @@ using RabbitMQ.Client.Framing.Impl; using RabbitMQ.Client.Impl; -namespace RabbitMQ.Client; - -#nullable enable -/// -/// AMQP specification content header properties for content class "basic". -/// -public struct BasicProperties : IBasicProperties, IAmqpHeader +namespace RabbitMQ.Client { - public string? ContentType { get; set; } - public string? ContentEncoding { get; set; } - public IDictionary? Headers { get; set; } - public DeliveryModes DeliveryMode { get; set; } - public byte Priority { get; set; } - public string? CorrelationId { get; set; } - public string? ReplyTo { get; set; } - public string? Expiration { get; set; } - public string? MessageId { get; set; } - public AmqpTimestamp Timestamp { get; set; } - public string? Type { get; set; } - public string? UserId { get; set; } - public string? AppId { get; set; } - public string? ClusterId { get; set; } - - public bool Persistent +#nullable enable + /// + /// AMQP specification content header properties for content class "basic". + /// + public struct BasicProperties : IBasicProperties, IAmqpHeader { - readonly get + public string? ContentType { get; set; } + public string? ContentEncoding { get; set; } + public IDictionary? Headers { get; set; } + public DeliveryModes DeliveryMode { get; set; } + public byte Priority { get; set; } + public string? CorrelationId { get; set; } + public string? ReplyTo { get; set; } + public string? Expiration { get; set; } + public string? MessageId { get; set; } + public AmqpTimestamp Timestamp { get; set; } + public string? Type { get; set; } + public string? UserId { get; set; } + public string? AppId { get; set; } + public string? ClusterId { get; set; } + + public bool Persistent { - return DeliveryMode == DeliveryModes.Persistent; + readonly get + { + return DeliveryMode == DeliveryModes.Persistent; + } + + set + { + DeliveryMode = value ? DeliveryModes.Persistent : DeliveryModes.Transient; + } } - set + public PublicationAddress? ReplyToAddress { - DeliveryMode = value ? DeliveryModes.Persistent : DeliveryModes.Transient; + readonly get + { + PublicationAddress.TryParse(ReplyTo, out PublicationAddress result); + return result; + } + + set { ReplyTo = value?.ToString(); } } - } - public PublicationAddress? ReplyToAddress - { - readonly get + public BasicProperties(in ReadOnlyBasicProperties input) { - PublicationAddress.TryParse(ReplyTo, out PublicationAddress result); - return result; + ContentType = input.ContentType; + ContentEncoding = input.ContentEncoding; + Headers = input.Headers; + DeliveryMode = input.DeliveryMode; + Priority = input.Priority; + CorrelationId = input.CorrelationId; + ReplyTo = input.ReplyTo; + Expiration = input.Expiration; + MessageId = input.MessageId; + Timestamp = input.Timestamp; + Type = input.Type; + UserId = input.UserId; + AppId = input.AppId; + ClusterId = input.ClusterId; } - set { ReplyTo = value?.ToString(); } - } + public void ClearContentType() => ContentType = default; + public void ClearContentEncoding() => ContentEncoding = default; + public void ClearHeaders() => Headers = default; + public void ClearDeliveryMode() => DeliveryMode = default; + public void ClearPriority() => Priority = default; + public void ClearCorrelationId() => CorrelationId = default; + public void ClearReplyTo() => ReplyTo = default; + public void ClearExpiration() => Expiration = default; + public void ClearMessageId() => MessageId = default; + public void ClearTimestamp() => Timestamp = default; + public void ClearType() => Type = default; + public void ClearUserId() => UserId = default; + public void ClearAppId() => AppId = default; + public void ClearClusterId() => ClusterId = default; - public BasicProperties(in ReadOnlyBasicProperties input) - { - ContentType = input.ContentType; - ContentEncoding = input.ContentEncoding; - Headers = input.Headers; - DeliveryMode = input.DeliveryMode; - Priority = input.Priority; - CorrelationId = input.CorrelationId; - ReplyTo = input.ReplyTo; - Expiration = input.Expiration; - MessageId = input.MessageId; - Timestamp = input.Timestamp; - Type = input.Type; - UserId = input.UserId; - AppId = input.AppId; - ClusterId = input.ClusterId; - } + public readonly bool IsContentTypePresent() => ContentType != default; + public readonly bool IsContentEncodingPresent() => ContentEncoding != default; + public readonly bool IsHeadersPresent() => Headers != default; + public readonly bool IsDeliveryModePresent() => DeliveryMode != default; + public readonly bool IsPriorityPresent() => Priority != default; + public readonly bool IsCorrelationIdPresent() => CorrelationId != default; + public readonly bool IsReplyToPresent() => ReplyTo != default; + public readonly bool IsExpirationPresent() => Expiration != default; + public readonly bool IsMessageIdPresent() => MessageId != default; + public readonly bool IsTimestampPresent() => Timestamp != default; + public readonly bool IsTypePresent() => Type != default; + public readonly bool IsUserIdPresent() => UserId != default; + public readonly bool IsAppIdPresent() => AppId != default; + public readonly bool IsClusterIdPresent() => ClusterId != default; - public void ClearContentType() => ContentType = default; - public void ClearContentEncoding() => ContentEncoding = default; - public void ClearHeaders() => Headers = default; - public void ClearDeliveryMode() => DeliveryMode = default; - public void ClearPriority() => Priority = default; - public void ClearCorrelationId() => CorrelationId = default; - public void ClearReplyTo() => ReplyTo = default; - public void ClearExpiration() => Expiration = default; - public void ClearMessageId() => MessageId = default; - public void ClearTimestamp() => Timestamp = default; - public void ClearType() => Type = default; - public void ClearUserId() => UserId = default; - public void ClearAppId() => AppId = default; - public void ClearClusterId() => ClusterId = default; + ushort IAmqpHeader.ProtocolClassId => ClassConstants.Basic; - public readonly bool IsContentTypePresent() => ContentType != default; - public readonly bool IsContentEncodingPresent() => ContentEncoding != default; - public readonly bool IsHeadersPresent() => Headers != default; - public readonly bool IsDeliveryModePresent() => DeliveryMode != default; - public readonly bool IsPriorityPresent() => Priority != default; - public readonly bool IsCorrelationIdPresent() => CorrelationId != default; - public readonly bool IsReplyToPresent() => ReplyTo != default; - public readonly bool IsExpirationPresent() => Expiration != default; - public readonly bool IsMessageIdPresent() => MessageId != default; - public readonly bool IsTimestampPresent() => Timestamp != default; - public readonly bool IsTypePresent() => Type != default; - public readonly bool IsUserIdPresent() => UserId != default; - public readonly bool IsAppIdPresent() => AppId != default; - public readonly bool IsClusterIdPresent() => ClusterId != default; + //---------------------------------- + // First byte + //---------------------------------- + internal const byte ContentTypeBit = 7; + internal const byte ContentEncodingBit = 6; + internal const byte HeaderBit = 5; + internal const byte DeliveryModeBit = 4; + internal const byte PriorityBit = 3; + internal const byte CorrelationIdBit = 2; + internal const byte ReplyToBit = 1; + internal const byte ExpirationBit = 0; - ushort IAmqpHeader.ProtocolClassId => ClassConstants.Basic; + //---------------------------------- + // Second byte + //---------------------------------- + internal const byte MessageIdBit = 7; + internal const byte TimestampBit = 6; + internal const byte TypeBit = 5; + internal const byte UserIdBit = 4; + internal const byte AppIdBit = 3; + internal const byte ClusterIdBit = 2; - //---------------------------------- - // First byte - //---------------------------------- - internal const byte ContentTypeBit = 7; - internal const byte ContentEncodingBit = 6; - internal const byte HeaderBit = 5; - internal const byte DeliveryModeBit = 4; - internal const byte PriorityBit = 3; - internal const byte CorrelationIdBit = 2; - internal const byte ReplyToBit = 1; - internal const byte ExpirationBit = 0; + readonly int IAmqpWriteable.WriteTo(Span span) + { + int offset = 2; + ref byte bitValue = ref span.GetStart(); + bitValue = 0; + if (IsContentTypePresent()) + { + bitValue.SetBit(ContentTypeBit); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), ContentType); + } - //---------------------------------- - // Second byte - //---------------------------------- - internal const byte MessageIdBit = 7; - internal const byte TimestampBit = 6; - internal const byte TypeBit = 5; - internal const byte UserIdBit = 4; - internal const byte AppIdBit = 3; - internal const byte ClusterIdBit = 2; + if (IsContentEncodingPresent()) + { + bitValue.SetBit(ContentEncodingBit); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), ContentEncoding); + } - readonly int IAmqpWriteable.WriteTo(Span span) - { - int offset = 2; - ref byte bitValue = ref span.GetStart(); - bitValue = 0; - if (IsContentTypePresent()) - { - bitValue.SetBit(ContentTypeBit); - offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), ContentType); - } + if (IsHeadersPresent()) + { + bitValue.SetBit(HeaderBit); + offset += WireFormatting.WriteTable(ref span.GetOffset(offset), Headers); + } - if (IsContentEncodingPresent()) - { - bitValue.SetBit(ContentEncodingBit); - offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), ContentEncoding); - } + if (IsDeliveryModePresent()) + { + bitValue.SetBit(DeliveryModeBit); + span.GetOffset(offset++) = (byte)DeliveryMode; + } - if (IsHeadersPresent()) - { - bitValue.SetBit(HeaderBit); - offset += WireFormatting.WriteTable(ref span.GetOffset(offset), Headers); - } + if (IsPriorityPresent()) + { + bitValue.SetBit(PriorityBit); + span.GetOffset(offset++) = Priority; + } - if (IsDeliveryModePresent()) - { - bitValue.SetBit(DeliveryModeBit); - span.GetOffset(offset++) = (byte)DeliveryMode; - } + if (IsCorrelationIdPresent()) + { + bitValue.SetBit(CorrelationIdBit); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), CorrelationId); + } - if (IsPriorityPresent()) - { - bitValue.SetBit(PriorityBit); - span.GetOffset(offset++) = Priority; - } + if (IsReplyToPresent()) + { + bitValue.SetBit(ReplyToBit); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), ReplyTo); + } - if (IsCorrelationIdPresent()) - { - bitValue.SetBit(CorrelationIdBit); - offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), CorrelationId); - } + if (IsExpirationPresent()) + { + bitValue.SetBit(ExpirationBit); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), Expiration); + } - if (IsReplyToPresent()) - { - bitValue.SetBit(ReplyToBit); - offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), ReplyTo); - } + bitValue = ref span.GetOffset(1); + bitValue = 0; + if (IsMessageIdPresent()) + { + bitValue.SetBit(MessageIdBit); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), MessageId); + } - if (IsExpirationPresent()) - { - bitValue.SetBit(ExpirationBit); - offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), Expiration); - } + if (IsTimestampPresent()) + { + bitValue.SetBit(TimestampBit); + offset += WireFormatting.WriteTimestamp(ref span.GetOffset(offset), Timestamp); + } - bitValue = ref span.GetOffset(1); - bitValue = 0; - if (IsMessageIdPresent()) - { - bitValue.SetBit(MessageIdBit); - offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), MessageId); - } + if (IsTypePresent()) + { + bitValue.SetBit(TypeBit); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), Type); + } - if (IsTimestampPresent()) - { - bitValue.SetBit(TimestampBit); - offset += WireFormatting.WriteTimestamp(ref span.GetOffset(offset), Timestamp); - } + if (IsUserIdPresent()) + { + bitValue.SetBit(UserIdBit); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), UserId); + } - if (IsTypePresent()) - { - bitValue.SetBit(TypeBit); - offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), Type); - } + if (IsAppIdPresent()) + { + bitValue.SetBit(AppIdBit); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), AppId); + } - if (IsUserIdPresent()) - { - bitValue.SetBit(UserIdBit); - offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), UserId); - } + if (IsClusterIdPresent()) + { + bitValue.SetBit(ClusterIdBit); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), ClusterId); + } - if (IsAppIdPresent()) - { - bitValue.SetBit(AppIdBit); - offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), AppId); + return offset; } - if (IsClusterIdPresent()) + readonly int IAmqpWriteable.GetRequiredBufferSize() { - bitValue.SetBit(ClusterIdBit); - offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), ClusterId); + int bufferSize = 2; // number of presence fields (14) in 2 bytes blocks + if (IsContentTypePresent()) { bufferSize += 1 + WireFormatting.GetByteCount(ContentType); } // _contentType in bytes + if (IsContentEncodingPresent()) { bufferSize += 1 + WireFormatting.GetByteCount(ContentEncoding); } // _contentEncoding in bytes + if (IsHeadersPresent()) { bufferSize += WireFormatting.GetTableByteCount(Headers); } // _headers in bytes + if (IsDeliveryModePresent()) { bufferSize++; } // _deliveryMode in bytes + if (IsPriorityPresent()) { bufferSize++; } // _priority in bytes + if (IsCorrelationIdPresent()) { bufferSize += 1 + WireFormatting.GetByteCount(CorrelationId); } // _correlationId in bytes + if (IsReplyToPresent()) { bufferSize += 1 + WireFormatting.GetByteCount(ReplyTo); } // _replyTo in bytes + if (IsExpirationPresent()) { bufferSize += 1 + WireFormatting.GetByteCount(Expiration); } // _expiration in bytes + if (IsMessageIdPresent()) { bufferSize += 1 + WireFormatting.GetByteCount(MessageId); } // _messageId in bytes + if (IsTimestampPresent()) { bufferSize += 8; } // _timestamp in bytes + if (IsTypePresent()) { bufferSize += 1 + WireFormatting.GetByteCount(Type); } // _type in bytes + if (IsUserIdPresent()) { bufferSize += 1 + WireFormatting.GetByteCount(UserId); } // _userId in bytes + if (IsAppIdPresent()) { bufferSize += 1 + WireFormatting.GetByteCount(AppId); } // _appId in bytes + if (IsClusterIdPresent()) { bufferSize += 1 + WireFormatting.GetByteCount(ClusterId); } // _clusterId in bytes + return bufferSize; } - - return offset; - } - - readonly int IAmqpWriteable.GetRequiredBufferSize() - { - int bufferSize = 2; // number of presence fields (14) in 2 bytes blocks - if (IsContentTypePresent()) { bufferSize += 1 + WireFormatting.GetByteCount(ContentType); } // _contentType in bytes - if (IsContentEncodingPresent()) { bufferSize += 1 + WireFormatting.GetByteCount(ContentEncoding); } // _contentEncoding in bytes - if (IsHeadersPresent()) { bufferSize += WireFormatting.GetTableByteCount(Headers); } // _headers in bytes - if (IsDeliveryModePresent()) { bufferSize++; } // _deliveryMode in bytes - if (IsPriorityPresent()) { bufferSize++; } // _priority in bytes - if (IsCorrelationIdPresent()) { bufferSize += 1 + WireFormatting.GetByteCount(CorrelationId); } // _correlationId in bytes - if (IsReplyToPresent()) { bufferSize += 1 + WireFormatting.GetByteCount(ReplyTo); } // _replyTo in bytes - if (IsExpirationPresent()) { bufferSize += 1 + WireFormatting.GetByteCount(Expiration); } // _expiration in bytes - if (IsMessageIdPresent()) { bufferSize += 1 + WireFormatting.GetByteCount(MessageId); } // _messageId in bytes - if (IsTimestampPresent()) { bufferSize += 8; } // _timestamp in bytes - if (IsTypePresent()) { bufferSize += 1 + WireFormatting.GetByteCount(Type); } // _type in bytes - if (IsUserIdPresent()) { bufferSize += 1 + WireFormatting.GetByteCount(UserId); } // _userId in bytes - if (IsAppIdPresent()) { bufferSize += 1 + WireFormatting.GetByteCount(AppId); } // _appId in bytes - if (IsClusterIdPresent()) { bufferSize += 1 + WireFormatting.GetByteCount(ClusterId); } // _clusterId in bytes - return bufferSize; } } diff --git a/projects/RabbitMQ.Client/client/api/BinaryTableValue.cs b/projects/RabbitMQ.Client/client/api/BinaryTableValue.cs index 153b9e5558..a2abc1f424 100644 --- a/projects/RabbitMQ.Client/client/api/BinaryTableValue.cs +++ b/projects/RabbitMQ.Client/client/api/BinaryTableValue.cs @@ -29,56 +29,57 @@ // Copyright (c) 2007-2020 VMware, Inc. All rights reserved. //--------------------------------------------------------------------------- -namespace RabbitMQ.Client; - -/// Wrapper for a byte[]. May appear as values read from -///and written to AMQP field tables. -/// -/// -/// The sole reason for the existence of this class is to permit -/// encoding of byte[] as 'x' in AMQP field tables, an extension -/// to the specification that is part of the tentative JMS mapping -/// implemented by QPid. -/// -/// -/// Instances of this object may be found as values held in -/// IDictionary instances returned from -/// RabbitMQ.Client.Impl.WireFormatting.ReadTable, e.g. as part of -/// IBasicProperties.Headers tables. Likewise, instances may be -/// set as values in an IDictionary table to be encoded by -/// RabbitMQ.Client.Impl.WireFormatting.WriteTable. -/// -/// -/// When an instance of this class is encoded/decoded, the type -/// tag 'x' is used in the on-the-wire representation. The AMQP -/// standard type tag 'S' is decoded to a raw byte[], and a raw -/// byte[] is encoded as 'S'. Instances of System.String are -/// converted to a UTF-8 binary representation, and then encoded -/// using tag 'S'. In order to force the use of tag 'x', instances -/// of this class must be used. -/// -/// -public class BinaryTableValue +namespace RabbitMQ.Client { - /// - /// Creates a new instance of the with null for its Bytes property. - /// - public BinaryTableValue() : this(null) + /// Wrapper for a byte[]. May appear as values read from + ///and written to AMQP field tables. + /// + /// + /// The sole reason for the existence of this class is to permit + /// encoding of byte[] as 'x' in AMQP field tables, an extension + /// to the specification that is part of the tentative JMS mapping + /// implemented by QPid. + /// + /// + /// Instances of this object may be found as values held in + /// IDictionary instances returned from + /// RabbitMQ.Client.Impl.WireFormatting.ReadTable, e.g. as part of + /// IBasicProperties.Headers tables. Likewise, instances may be + /// set as values in an IDictionary table to be encoded by + /// RabbitMQ.Client.Impl.WireFormatting.WriteTable. + /// + /// + /// When an instance of this class is encoded/decoded, the type + /// tag 'x' is used in the on-the-wire representation. The AMQP + /// standard type tag 'S' is decoded to a raw byte[], and a raw + /// byte[] is encoded as 'S'. Instances of System.String are + /// converted to a UTF-8 binary representation, and then encoded + /// using tag 'S'. In order to force the use of tag 'x', instances + /// of this class must be used. + /// + /// + public class BinaryTableValue { - } + /// + /// Creates a new instance of the with null for its Bytes property. + /// + public BinaryTableValue() : this(null) + { + } - /// - /// Creates a new instance of the . - /// - /// The wrapped byte array, as decoded or as to be encoded. - public BinaryTableValue(byte[] bytes) - { - Bytes = bytes; - } + /// + /// Creates a new instance of the . + /// + /// The wrapped byte array, as decoded or as to be encoded. + public BinaryTableValue(byte[] bytes) + { + Bytes = bytes; + } - /// - /// The wrapped byte array, as decoded or as to be encoded. - /// - public byte[] Bytes { get; set; } + /// + /// The wrapped byte array, as decoded or as to be encoded. + /// + public byte[] Bytes { get; set; } + } } diff --git a/projects/RabbitMQ.Client/client/api/CachedString.cs b/projects/RabbitMQ.Client/client/api/CachedString.cs index d83ba653d7..16e33a1fb7 100644 --- a/projects/RabbitMQ.Client/client/api/CachedString.cs +++ b/projects/RabbitMQ.Client/client/api/CachedString.cs @@ -1,62 +1,63 @@ using System; using System.Text; -namespace RabbitMQ.Client; - -/// -/// Caches a string's byte representation to be used for certain methods like IModel.BasicPublish/>. -/// -public sealed class CachedString +namespace RabbitMQ.Client { - public static readonly CachedString Empty = new CachedString(string.Empty, ReadOnlyMemory.Empty); - - /// - /// The string value to cache. - /// - public readonly string Value; - /// - /// Gets the bytes representing the . - /// - public readonly ReadOnlyMemory Bytes; - /// - /// Creates a new based on the provided string. + /// Caches a string's byte representation to be used for certain methods like IModel.BasicPublish/>. /// - /// The string to cache. - public CachedString(string value) + public sealed class CachedString { - Value = value; - Bytes = Encoding.UTF8.GetBytes(value); - } + public static readonly CachedString Empty = new CachedString(string.Empty, ReadOnlyMemory.Empty); - /// - /// Creates a new based on the provided bytes. - /// - /// The bytes. - public CachedString(ReadOnlyMemory bytes) - { + /// + /// The string value to cache. + /// + public readonly string Value; + /// + /// Gets the bytes representing the . + /// + public readonly ReadOnlyMemory Bytes; + + /// + /// Creates a new based on the provided string. + /// + /// The string to cache. + public CachedString(string value) + { + Value = value; + Bytes = Encoding.UTF8.GetBytes(value); + } + + /// + /// Creates a new based on the provided bytes. + /// + /// The bytes. + public CachedString(ReadOnlyMemory bytes) + { #if !NETSTANDARD - Value = Encoding.UTF8.GetString(bytes.Span); + Value = Encoding.UTF8.GetString(bytes.Span); #else - unsafe - { - fixed (byte* bytePointer = bytes.Span) + unsafe { - Value = Encoding.UTF8.GetString(bytePointer, bytes.Length); + fixed (byte* bytePointer = bytes.Span) + { + Value = Encoding.UTF8.GetString(bytePointer, bytes.Length); + } } - } #endif - Bytes = bytes; - } + Bytes = bytes; + } - /// - /// Creates a new based on the provided values. - /// - /// The string to cache. - /// The byte representation of the string value. - public CachedString(string value, ReadOnlyMemory bytes) - { - Value = value; - Bytes = bytes; + /// + /// Creates a new based on the provided values. + /// + /// The string to cache. + /// The byte representation of the string value. + public CachedString(string value, ReadOnlyMemory bytes) + { + Value = value; + Bytes = bytes; + } } } diff --git a/projects/RabbitMQ.Client/client/api/ConnectionConfig.cs b/projects/RabbitMQ.Client/client/api/ConnectionConfig.cs index f260b37c50..596a341d14 100644 --- a/projects/RabbitMQ.Client/client/api/ConnectionConfig.cs +++ b/projects/RabbitMQ.Client/client/api/ConnectionConfig.cs @@ -34,120 +34,121 @@ using RabbitMQ.Client.Impl; -namespace RabbitMQ.Client; - -#nullable enable -/// -/// The configuration of a connection. -/// -public sealed class ConnectionConfig +namespace RabbitMQ.Client { +#nullable enable /// - /// Virtual host to access during this connection. - /// - public string VirtualHost { get; } - - /// - /// Username to use when authenticating to the server. - /// - public string UserName { get; } - - /// - /// Password to use when authenticating to the server. - /// - public string Password { get; internal set; } - - /// - /// SASL auth mechanisms to use. - /// - public IList AuthMechanisms { get; } - - /// - /// Dictionary of client properties to be sent to the server. - /// - public IDictionary ClientProperties { get; } - - /// - /// Default client provided name to be used for connections. - /// - public string? ClientProvidedName { get; } - - /// - /// Maximum channel number to ask for. - /// - public ushort MaxChannelCount { get; } - /// - /// Frame-max parameter to ask for (in bytes). - /// - public uint MaxFrameSize { get; } - - /// - /// Set to false to make automatic connection recovery not recover topology (exchanges, queues, bindings, etc). - /// - public bool TopologyRecoveryEnabled { get; } - - /// - /// Amount of time client will wait for before re-trying to recover connection. - /// - public TimeSpan NetworkRecoveryInterval { get; } - - /// - /// Heartbeat timeout to use when negotiating with the server. - /// - public TimeSpan HeartbeatInterval { get; } - - /// - /// Amount of time protocol operations (e.g. queue.declare) are allowed to take before timing out. - /// - public TimeSpan ContinuationTimeout { get; } - - /// - /// Amount of time protocol handshake operations are allowed to take before timing out. - /// - - public TimeSpan HandshakeContinuationTimeout { get; } - /// - /// Timeout setting for connection attempts. - /// - public TimeSpan RequestedConnectionTimeout { get; } - - /// - /// Set to true will enable an asynchronous consumer dispatcher which is compatible with . - /// - public bool DispatchConsumersAsync { get; } - - /// - /// Set to a value greater than one to enable concurrent processing. For a concurrency greater than one - /// will be offloaded to the worker thread pool so it is important to choose the value for the concurrency wisely to avoid thread pool overloading. - /// can handle concurrency much more efficiently due to the non-blocking nature of the consumer. + /// The configuration of a connection. /// - public int DispatchConsumerConcurrency { get; } - - internal Func FrameHandlerFactory { get; } - - internal ConnectionConfig(string virtualHost, string userName, string password, IList authMechanisms, - IDictionary clientProperties, string? clientProvidedName, - ushort maxChannelCount, uint maxFrameSize, bool topologyRecoveryEnabled, - TimeSpan networkRecoveryInterval, TimeSpan heartbeatInterval, TimeSpan continuationTimeout, TimeSpan handshakeContinuationTimeout, TimeSpan requestedConnectionTimeout, - bool dispatchConsumersAsync, int dispatchConsumerConcurrency, - Func frameHandlerFactory) + public sealed class ConnectionConfig { - VirtualHost = virtualHost; - UserName = userName; - Password = password; - AuthMechanisms = authMechanisms; - ClientProperties = clientProperties; - ClientProvidedName = clientProvidedName; - MaxChannelCount = maxChannelCount; - MaxFrameSize = maxFrameSize; - TopologyRecoveryEnabled = topologyRecoveryEnabled; - NetworkRecoveryInterval = networkRecoveryInterval; - HeartbeatInterval = heartbeatInterval; - ContinuationTimeout = continuationTimeout; - HandshakeContinuationTimeout = handshakeContinuationTimeout; - RequestedConnectionTimeout = requestedConnectionTimeout; - DispatchConsumersAsync = dispatchConsumersAsync; - DispatchConsumerConcurrency = dispatchConsumerConcurrency; - FrameHandlerFactory = frameHandlerFactory; + /// + /// Virtual host to access during this connection. + /// + public string VirtualHost { get; } + + /// + /// Username to use when authenticating to the server. + /// + public string UserName { get; } + + /// + /// Password to use when authenticating to the server. + /// + public string Password { get; internal set; } + + /// + /// SASL auth mechanisms to use. + /// + public IList AuthMechanisms { get; } + + /// + /// Dictionary of client properties to be sent to the server. + /// + public IDictionary ClientProperties { get; } + + /// + /// Default client provided name to be used for connections. + /// + public string? ClientProvidedName { get; } + + /// + /// Maximum channel number to ask for. + /// + public ushort MaxChannelCount { get; } + /// + /// Frame-max parameter to ask for (in bytes). + /// + public uint MaxFrameSize { get; } + + /// + /// Set to false to make automatic connection recovery not recover topology (exchanges, queues, bindings, etc). + /// + public bool TopologyRecoveryEnabled { get; } + + /// + /// Amount of time client will wait for before re-trying to recover connection. + /// + public TimeSpan NetworkRecoveryInterval { get; } + + /// + /// Heartbeat timeout to use when negotiating with the server. + /// + public TimeSpan HeartbeatInterval { get; } + + /// + /// Amount of time protocol operations (e.g. queue.declare) are allowed to take before timing out. + /// + public TimeSpan ContinuationTimeout { get; } + + /// + /// Amount of time protocol handshake operations are allowed to take before timing out. + /// + + public TimeSpan HandshakeContinuationTimeout { get; } + /// + /// Timeout setting for connection attempts. + /// + public TimeSpan RequestedConnectionTimeout { get; } + + /// + /// Set to true will enable an asynchronous consumer dispatcher which is compatible with . + /// + public bool DispatchConsumersAsync { get; } + + /// + /// Set to a value greater than one to enable concurrent processing. For a concurrency greater than one + /// will be offloaded to the worker thread pool so it is important to choose the value for the concurrency wisely to avoid thread pool overloading. + /// can handle concurrency much more efficiently due to the non-blocking nature of the consumer. + /// + public int DispatchConsumerConcurrency { get; } + + internal Func FrameHandlerFactory { get; } + + internal ConnectionConfig(string virtualHost, string userName, string password, IList authMechanisms, + IDictionary clientProperties, string? clientProvidedName, + ushort maxChannelCount, uint maxFrameSize, bool topologyRecoveryEnabled, + TimeSpan networkRecoveryInterval, TimeSpan heartbeatInterval, TimeSpan continuationTimeout, TimeSpan handshakeContinuationTimeout, TimeSpan requestedConnectionTimeout, + bool dispatchConsumersAsync, int dispatchConsumerConcurrency, + Func frameHandlerFactory) + { + VirtualHost = virtualHost; + UserName = userName; + Password = password; + AuthMechanisms = authMechanisms; + ClientProperties = clientProperties; + ClientProvidedName = clientProvidedName; + MaxChannelCount = maxChannelCount; + MaxFrameSize = maxFrameSize; + TopologyRecoveryEnabled = topologyRecoveryEnabled; + NetworkRecoveryInterval = networkRecoveryInterval; + HeartbeatInterval = heartbeatInterval; + ContinuationTimeout = continuationTimeout; + HandshakeContinuationTimeout = handshakeContinuationTimeout; + RequestedConnectionTimeout = requestedConnectionTimeout; + DispatchConsumersAsync = dispatchConsumersAsync; + DispatchConsumerConcurrency = dispatchConsumerConcurrency; + FrameHandlerFactory = frameHandlerFactory; + } } } diff --git a/projects/RabbitMQ.Client/client/api/ConnectionFactory.cs b/projects/RabbitMQ.Client/client/api/ConnectionFactory.cs index 98a85152b0..4d4793492b 100644 --- a/projects/RabbitMQ.Client/client/api/ConnectionFactory.cs +++ b/projects/RabbitMQ.Client/client/api/ConnectionFactory.cs @@ -40,592 +40,593 @@ using RabbitMQ.Client.Framing.Impl; using RabbitMQ.Client.Impl; -namespace RabbitMQ.Client; - -/// Main entry point to the RabbitMQ .NET AMQP client -///API. Constructs instances. -/// -/// -/// A simple example of connecting to a broker: -/// -/// -/// ConnectionFactory factory = new ConnectionFactory(); -/// // -/// // The next five lines are optional: -/// factory.UserName = ConnectionFactory.DefaultUser; -/// factory.Password = ConnectionFactory.DefaultPass; -/// factory.VirtualHost = ConnectionFactory.DefaultVHost; -/// factory.HostName = hostName; -/// factory.Port = AmqpTcpEndpoint.UseDefaultPort; -/// // -/// IConnection conn = factory.CreateConnection(); -/// // -/// IModel ch = conn.CreateModel(); -/// // -/// // ... use ch's IModel methods ... -/// // -/// ch.Close(Constants.ReplySuccess, "Closing the channel"); -/// conn.Close(Constants.ReplySuccess, "Closing the connection"); -/// -/// -///The same example, written more compactly with AMQP URIs: -/// -/// -/// ConnectionFactory factory = new ConnectionFactory(); -/// factory.Uri = new Uri("amqp://localhost"); -/// IConnection conn = factory.CreateConnection(); -/// ... -/// -/// -/// Please see also the API overview and tutorial in the User Guide. -/// -/// -///Note that the Uri property takes a string representation of an -///AMQP URI. Omitted URI parts will take default values. The -///host part of the URI cannot be omitted and URIs of the form -///"amqp://foo/" (note the trailing slash) also represent the -///default virtual host. The latter issue means that virtual -///hosts with an empty name are not addressable. -public sealed class ConnectionFactory : ConnectionFactoryBase, IConnectionFactory +namespace RabbitMQ.Client { - /// - /// Default value for the desired maximum channel number. Default: 2047. - /// - public const ushort DefaultChannelMax = 2047; - - /// - /// Default value for connection attempt timeout. - /// - public static readonly TimeSpan DefaultConnectionTimeout = TimeSpan.FromSeconds(30); - - /// - /// Default value for the desired maximum frame size. Default is 0 ("no limit"). - /// - public const uint DefaultFrameMax = 0; - - /// - /// Default value for desired heartbeat interval. Default is 60 seconds, - /// TimeSpan.Zero means "heartbeats are disabled". - /// - public static readonly TimeSpan DefaultHeartbeat = TimeSpan.FromSeconds(60); - - /// - /// Default password (value: "guest"). - /// - public const string DefaultPass = "guest"; - - /// - /// Default user name (value: "guest"). - /// - public const string DefaultUser = "guest"; - - /// - /// Default virtual host (value: "/"). - /// - public const string DefaultVHost = "/"; - - /// - /// TLS versions enabled by default: TLSv1.2, v1.1, v1.0. - /// - public static SslProtocols DefaultAmqpUriSslProtocols { get; set; } = SslProtocols.None; - - /// - /// The AMQP URI SSL protocols. - /// - public SslProtocols AmqpUriSslProtocols { get; set; } = DefaultAmqpUriSslProtocols; - - /// - /// Default SASL auth mechanisms to use. - /// - public static readonly IList DefaultAuthMechanisms = new List(1) { new PlainMechanismFactory() }; - - /// - /// SASL auth mechanisms to use. - /// - public IList AuthMechanisms { get; set; } = DefaultAuthMechanisms; - - /// - /// Address family used by default. - /// Use to force to IPv4. - /// Use to force to IPv6. - /// Or use to attempt both IPv6 and IPv4. - /// - public static System.Net.Sockets.AddressFamily DefaultAddressFamily { get; set; } - - /// - /// Set to false to disable automatic connection recovery. - /// Defaults to true. - /// - public bool AutomaticRecoveryEnabled { get; set; } = true; - - /// - /// Set to true will enable an asynchronous consumer dispatcher which is compatible with . - /// Defaults to false. - /// - public bool DispatchConsumersAsync { get; set; } = false; - - /// - /// Set to a value greater than one to enable concurrent processing. For a concurrency greater than one - /// will be offloaded to the worker thread pool so it is important to choose the value for the concurrency wisely to avoid thread pool overloading. - /// can handle concurrency much more efficiently due to the non-blocking nature of the consumer. - /// Defaults to 1. - /// - /// For concurrency greater than one this removes the guarantee that consumers handle messages in the order they receive them. - /// In addition to that consumers need to be thread/concurrency safe. - public int ConsumerDispatchConcurrency { get; set; } = 1; - - /// The host to connect to. - public string HostName { get; set; } = "localhost"; - - /// - /// Amount of time client will wait for before re-trying to recover connection. - /// - public TimeSpan NetworkRecoveryInterval { get; set; } = TimeSpan.FromSeconds(5); - - private TimeSpan _handshakeContinuationTimeout = TimeSpan.FromSeconds(10); - private TimeSpan _continuationTimeout = TimeSpan.FromSeconds(20); - - // just here to hold the value that was set through the setter - private Uri _uri; - - /// - /// Amount of time protocol handshake operations are allowed to take before - /// timing out. - /// - public TimeSpan HandshakeContinuationTimeout + /// Main entry point to the RabbitMQ .NET AMQP client + ///API. Constructs instances. + /// + /// + /// A simple example of connecting to a broker: + /// + /// + /// ConnectionFactory factory = new ConnectionFactory(); + /// // + /// // The next five lines are optional: + /// factory.UserName = ConnectionFactory.DefaultUser; + /// factory.Password = ConnectionFactory.DefaultPass; + /// factory.VirtualHost = ConnectionFactory.DefaultVHost; + /// factory.HostName = hostName; + /// factory.Port = AmqpTcpEndpoint.UseDefaultPort; + /// // + /// IConnection conn = factory.CreateConnection(); + /// // + /// IModel ch = conn.CreateModel(); + /// // + /// // ... use ch's IModel methods ... + /// // + /// ch.Close(Constants.ReplySuccess, "Closing the channel"); + /// conn.Close(Constants.ReplySuccess, "Closing the connection"); + /// + /// + ///The same example, written more compactly with AMQP URIs: + /// + /// + /// ConnectionFactory factory = new ConnectionFactory(); + /// factory.Uri = new Uri("amqp://localhost"); + /// IConnection conn = factory.CreateConnection(); + /// ... + /// + /// + /// Please see also the API overview and tutorial in the User Guide. + /// + /// + ///Note that the Uri property takes a string representation of an + ///AMQP URI. Omitted URI parts will take default values. The + ///host part of the URI cannot be omitted and URIs of the form + ///"amqp://foo/" (note the trailing slash) also represent the + ///default virtual host. The latter issue means that virtual + ///hosts with an empty name are not addressable. + public sealed class ConnectionFactory : ConnectionFactoryBase, IConnectionFactory { - get { return _handshakeContinuationTimeout; } - set { _handshakeContinuationTimeout = value; } - } - - /// - /// Amount of time protocol operations (e.g. queue.declare) are allowed to take before - /// timing out. - /// - public TimeSpan ContinuationTimeout - { - get { return _continuationTimeout; } - set { _continuationTimeout = value; } - } - - /// - /// Factory function for creating the - /// used to generate a list of endpoints for the ConnectionFactory - /// to try in order. - /// The default value creates an instance of the - /// using the list of endpoints passed in. The DefaultEndpointResolver shuffles the - /// provided list each time it is requested. - /// - public Func, IEndpointResolver> EndpointResolverFactory { get; set; } = - endpoints => new DefaultEndpointResolver(endpoints); - - /// - /// The port to connect on. - /// indicates the default for the protocol should be used. - /// - public int Port { get; set; } = AmqpTcpEndpoint.UseDefaultPort; - - /// - /// Timeout setting for connection attempts. - /// - public TimeSpan RequestedConnectionTimeout { get; set; } = DefaultConnectionTimeout; - - /// - /// Timeout setting for socket read operations. - /// - public TimeSpan SocketReadTimeout { get; set; } = DefaultConnectionTimeout; - - /// - /// Timeout setting for socket write operations. - /// - public TimeSpan SocketWriteTimeout { get; set; } = DefaultConnectionTimeout; - - /// - /// TLS options setting. - /// - public SslOption Ssl { get; set; } = new SslOption(); - - /// - /// Set to false to make automatic connection recovery not recover topology (exchanges, queues, bindings, etc). - /// Defaults to true. - /// - public bool TopologyRecoveryEnabled { get; set; } = true; - - /// - /// Construct a fresh instance, with all fields set to their respective defaults. - /// - public ConnectionFactory() - { - ClientProperties = new Dictionary(DefaultClientProperties); - } - - /// - /// Connection endpoint. - /// - public AmqpTcpEndpoint Endpoint - { - get { return new AmqpTcpEndpoint(HostName, Port, Ssl); } - set + /// + /// Default value for the desired maximum channel number. Default: 2047. + /// + public const ushort DefaultChannelMax = 2047; + + /// + /// Default value for connection attempt timeout. + /// + public static readonly TimeSpan DefaultConnectionTimeout = TimeSpan.FromSeconds(30); + + /// + /// Default value for the desired maximum frame size. Default is 0 ("no limit"). + /// + public const uint DefaultFrameMax = 0; + + /// + /// Default value for desired heartbeat interval. Default is 60 seconds, + /// TimeSpan.Zero means "heartbeats are disabled". + /// + public static readonly TimeSpan DefaultHeartbeat = TimeSpan.FromSeconds(60); + + /// + /// Default password (value: "guest"). + /// + public const string DefaultPass = "guest"; + + /// + /// Default user name (value: "guest"). + /// + public const string DefaultUser = "guest"; + + /// + /// Default virtual host (value: "/"). + /// + public const string DefaultVHost = "/"; + + /// + /// TLS versions enabled by default: TLSv1.2, v1.1, v1.0. + /// + public static SslProtocols DefaultAmqpUriSslProtocols { get; set; } = SslProtocols.None; + + /// + /// The AMQP URI SSL protocols. + /// + public SslProtocols AmqpUriSslProtocols { get; set; } = DefaultAmqpUriSslProtocols; + + /// + /// Default SASL auth mechanisms to use. + /// + public static readonly IList DefaultAuthMechanisms = new List(1) { new PlainMechanismFactory() }; + + /// + /// SASL auth mechanisms to use. + /// + public IList AuthMechanisms { get; set; } = DefaultAuthMechanisms; + + /// + /// Address family used by default. + /// Use to force to IPv4. + /// Use to force to IPv6. + /// Or use to attempt both IPv6 and IPv4. + /// + public static System.Net.Sockets.AddressFamily DefaultAddressFamily { get; set; } + + /// + /// Set to false to disable automatic connection recovery. + /// Defaults to true. + /// + public bool AutomaticRecoveryEnabled { get; set; } = true; + + /// + /// Set to true will enable an asynchronous consumer dispatcher which is compatible with . + /// Defaults to false. + /// + public bool DispatchConsumersAsync { get; set; } = false; + + /// + /// Set to a value greater than one to enable concurrent processing. For a concurrency greater than one + /// will be offloaded to the worker thread pool so it is important to choose the value for the concurrency wisely to avoid thread pool overloading. + /// can handle concurrency much more efficiently due to the non-blocking nature of the consumer. + /// Defaults to 1. + /// + /// For concurrency greater than one this removes the guarantee that consumers handle messages in the order they receive them. + /// In addition to that consumers need to be thread/concurrency safe. + public int ConsumerDispatchConcurrency { get; set; } = 1; + + /// The host to connect to. + public string HostName { get; set; } = "localhost"; + + /// + /// Amount of time client will wait for before re-trying to recover connection. + /// + public TimeSpan NetworkRecoveryInterval { get; set; } = TimeSpan.FromSeconds(5); + + private TimeSpan _handshakeContinuationTimeout = TimeSpan.FromSeconds(10); + private TimeSpan _continuationTimeout = TimeSpan.FromSeconds(20); + + // just here to hold the value that was set through the setter + private Uri _uri; + + /// + /// Amount of time protocol handshake operations are allowed to take before + /// timing out. + /// + public TimeSpan HandshakeContinuationTimeout { - Port = value.Port; - HostName = value.HostName; - Ssl = value.Ssl; + get { return _handshakeContinuationTimeout; } + set { _handshakeContinuationTimeout = value; } } - } - - /// - /// Dictionary of client properties to be sent to the server. - /// - public IDictionary ClientProperties { get; set; } - private static readonly Dictionary DefaultClientProperties = new Dictionary(5) - { - ["product"] = Encoding.UTF8.GetBytes("RabbitMQ"), - ["version"] = Encoding.UTF8.GetBytes(typeof(ConnectionFactory).Assembly.GetCustomAttribute().InformationalVersion), - ["platform"] = Encoding.UTF8.GetBytes(".NET"), - ["copyright"] = Encoding.UTF8.GetBytes("Copyright (c) 2007-2020 VMware, Inc."), - ["information"] = Encoding.UTF8.GetBytes("Licensed under the MPL. See https://www.rabbitmq.com/") - }; - - /// - /// Password to use when authenticating to the server. - /// - public string Password { get; set; } = DefaultPass; - - /// - /// Maximum channel number to ask for. - /// - public ushort RequestedChannelMax { get; set; } = DefaultChannelMax; - - /// - /// Frame-max parameter to ask for (in bytes). - /// - public uint RequestedFrameMax { get; set; } = DefaultFrameMax; - - /// - /// Heartbeat timeout to use when negotiating with the server. - /// - public TimeSpan RequestedHeartbeat { get; set; } = DefaultHeartbeat; - - /// - /// Username to use when authenticating to the server. - /// - public string UserName { get; set; } = DefaultUser; - - /// - /// Virtual host to access during this connection. - /// - public string VirtualHost { get; set; } = DefaultVHost; - - /// - /// The uri to use for the connection. - /// - public Uri Uri - { - get { return _uri; } - set { SetUri(value); } - } - - /// - /// Default client provided name to be used for connections. - /// - public string ClientProvidedName { get; set; } + /// + /// Amount of time protocol operations (e.g. queue.declare) are allowed to take before + /// timing out. + /// + public TimeSpan ContinuationTimeout + { + get { return _continuationTimeout; } + set { _continuationTimeout = value; } + } - /// - /// Given a list of mechanism names supported by the server, select a preferred mechanism, - /// or null if we have none in common. - /// - public IAuthMechanismFactory AuthMechanismFactory(IList mechanismNames) - { - // Our list is in order of preference, the server one is not. - for (int index = 0; index < AuthMechanisms.Count; index++) + /// + /// Factory function for creating the + /// used to generate a list of endpoints for the ConnectionFactory + /// to try in order. + /// The default value creates an instance of the + /// using the list of endpoints passed in. The DefaultEndpointResolver shuffles the + /// provided list each time it is requested. + /// + public Func, IEndpointResolver> EndpointResolverFactory { get; set; } = + endpoints => new DefaultEndpointResolver(endpoints); + + /// + /// The port to connect on. + /// indicates the default for the protocol should be used. + /// + public int Port { get; set; } = AmqpTcpEndpoint.UseDefaultPort; + + /// + /// Timeout setting for connection attempts. + /// + public TimeSpan RequestedConnectionTimeout { get; set; } = DefaultConnectionTimeout; + + /// + /// Timeout setting for socket read operations. + /// + public TimeSpan SocketReadTimeout { get; set; } = DefaultConnectionTimeout; + + /// + /// Timeout setting for socket write operations. + /// + public TimeSpan SocketWriteTimeout { get; set; } = DefaultConnectionTimeout; + + /// + /// TLS options setting. + /// + public SslOption Ssl { get; set; } = new SslOption(); + + /// + /// Set to false to make automatic connection recovery not recover topology (exchanges, queues, bindings, etc). + /// Defaults to true. + /// + public bool TopologyRecoveryEnabled { get; set; } = true; + + /// + /// Construct a fresh instance, with all fields set to their respective defaults. + /// + public ConnectionFactory() { - IAuthMechanismFactory factory = AuthMechanisms[index]; - string factoryName = factory.Name; + ClientProperties = new Dictionary(DefaultClientProperties); + } - for (int i = 0; i < mechanismNames.Count; i++) + /// + /// Connection endpoint. + /// + public AmqpTcpEndpoint Endpoint + { + get { return new AmqpTcpEndpoint(HostName, Port, Ssl); } + set { - if (string.Equals(mechanismNames[i], factoryName, StringComparison.OrdinalIgnoreCase)) - { - return factory; - } + Port = value.Port; + HostName = value.HostName; + Ssl = value.Ssl; } } - return null; - } - - /// - /// Create a connection to one of the endpoints provided by the IEndpointResolver - /// returned by the EndpointResolverFactory. By default the configured - /// hostname and port are used. - /// - /// - /// When the configured hostname was not reachable. - /// - public IConnection CreateConnection() - { - return CreateConnection(ClientProvidedName); - } - - /// - /// Create a connection to one of the endpoints provided by the IEndpointResolver - /// returned by the EndpointResolverFactory. By default the configured - /// hostname and port are used. - /// - /// - /// Application-specific connection name, will be displayed in the management UI - /// if RabbitMQ server supports it. This value doesn't have to be unique and cannot - /// be used as a connection identifier, e.g. in HTTP API requests. - /// This value is supposed to be human-readable. - /// - /// - /// When the configured hostname was not reachable. - /// - public IConnection CreateConnection(string clientProvidedName) - { - return CreateConnection(EndpointResolverFactory(LocalEndpoints()), clientProvidedName); - } + /// + /// Dictionary of client properties to be sent to the server. + /// + public IDictionary ClientProperties { get; set; } - /// - /// Create a connection using a list of hostnames using the configured port. - /// By default each hostname is tried in a random order until a successful connection is - /// found or the list is exhausted using the DefaultEndpointResolver. - /// The selection behaviour can be overridden by configuring the EndpointResolverFactory. - /// - /// - /// List of hostnames to use for the initial - /// connection and recovery. - /// - /// Open connection - /// - /// When no hostname was reachable. - /// - public IConnection CreateConnection(IList hostnames) - { - return CreateConnection(hostnames, ClientProvidedName); - } - - /// - /// Create a connection using a list of hostnames using the configured port. - /// By default each endpoint is tried in a random order until a successful connection is - /// found or the list is exhausted. - /// The selection behaviour can be overridden by configuring the EndpointResolverFactory. - /// - /// - /// List of hostnames to use for the initial - /// connection and recovery. - /// - /// - /// Application-specific connection name, will be displayed in the management UI - /// if RabbitMQ server supports it. This value doesn't have to be unique and cannot - /// be used as a connection identifier, e.g. in HTTP API requests. - /// This value is supposed to be human-readable. - /// - /// Open connection - /// - /// When no hostname was reachable. - /// - public IConnection CreateConnection(IList hostnames, string clientProvidedName) - { - IEnumerable endpoints = hostnames.Select(h => new AmqpTcpEndpoint(h, Port, Ssl)); - return CreateConnection(EndpointResolverFactory(endpoints), clientProvidedName); - } + private static readonly Dictionary DefaultClientProperties = new Dictionary(5) + { + ["product"] = Encoding.UTF8.GetBytes("RabbitMQ"), + ["version"] = Encoding.UTF8.GetBytes(typeof(ConnectionFactory).Assembly.GetCustomAttribute().InformationalVersion), + ["platform"] = Encoding.UTF8.GetBytes(".NET"), + ["copyright"] = Encoding.UTF8.GetBytes("Copyright (c) 2007-2020 VMware, Inc."), + ["information"] = Encoding.UTF8.GetBytes("Licensed under the MPL. See https://www.rabbitmq.com/") + }; + + /// + /// Password to use when authenticating to the server. + /// + public string Password { get; set; } = DefaultPass; + + /// + /// Maximum channel number to ask for. + /// + public ushort RequestedChannelMax { get; set; } = DefaultChannelMax; + + /// + /// Frame-max parameter to ask for (in bytes). + /// + public uint RequestedFrameMax { get; set; } = DefaultFrameMax; + + /// + /// Heartbeat timeout to use when negotiating with the server. + /// + public TimeSpan RequestedHeartbeat { get; set; } = DefaultHeartbeat; + + /// + /// Username to use when authenticating to the server. + /// + public string UserName { get; set; } = DefaultUser; + + /// + /// Virtual host to access during this connection. + /// + public string VirtualHost { get; set; } = DefaultVHost; + + /// + /// The uri to use for the connection. + /// + public Uri Uri + { + get { return _uri; } + set { SetUri(value); } + } - /// - /// Create a connection using a list of endpoints. By default each endpoint will be tried - /// in a random order until a successful connection is found or the list is exhausted. - /// The selection behaviour can be overridden by configuring the EndpointResolverFactory. - /// - /// - /// List of endpoints to use for the initial - /// connection and recovery. - /// - /// Open connection - /// - /// When no hostname was reachable. - /// - public IConnection CreateConnection(IList endpoints) - { - return CreateConnection(endpoints, ClientProvidedName); - } + /// + /// Default client provided name to be used for connections. + /// + public string ClientProvidedName { get; set; } - /// - /// Create a connection using a list of endpoints. By default each endpoint will be tried - /// in a random order until a successful connection is found or the list is exhausted. - /// The selection behaviour can be overridden by configuring the EndpointResolverFactory. - /// - /// - /// List of endpoints to use for the initial - /// connection and recovery. - /// - /// - /// Application-specific connection name, will be displayed in the management UI - /// if RabbitMQ server supports it. This value doesn't have to be unique and cannot - /// be used as a connection identifier, e.g. in HTTP API requests. - /// This value is supposed to be human-readable. - /// - /// Open connection - /// - /// When no hostname was reachable. - /// - public IConnection CreateConnection(IList endpoints, string clientProvidedName) - { - return CreateConnection(EndpointResolverFactory(endpoints), clientProvidedName); - } - - /// - /// Create a connection using an IEndpointResolver. - /// - /// - /// The endpointResolver that returns the endpoints to use for the connection attempt. - /// - /// - /// Application-specific connection name, will be displayed in the management UI - /// if RabbitMQ server supports it. This value doesn't have to be unique and cannot - /// be used as a connection identifier, e.g. in HTTP API requests. - /// This value is supposed to be human-readable. - /// - /// Open connection - /// - /// When no hostname was reachable. - /// - public IConnection CreateConnection(IEndpointResolver endpointResolver, string clientProvidedName) - { - ConnectionConfig config = CreateConfig(clientProvidedName); - try + /// + /// Given a list of mechanism names supported by the server, select a preferred mechanism, + /// or null if we have none in common. + /// + public IAuthMechanismFactory AuthMechanismFactory(IList mechanismNames) { - if (AutomaticRecoveryEnabled) + // Our list is in order of preference, the server one is not. + for (int index = 0; index < AuthMechanisms.Count; index++) { - return new AutorecoveringConnection(config, endpointResolver); + IAuthMechanismFactory factory = AuthMechanisms[index]; + string factoryName = factory.Name; + + for (int i = 0; i < mechanismNames.Count; i++) + { + if (string.Equals(mechanismNames[i], factoryName, StringComparison.OrdinalIgnoreCase)) + { + return factory; + } + } } - return new Connection(config, endpointResolver.SelectOne(CreateFrameHandler)); + return null; } - catch (Exception e) + + /// + /// Create a connection to one of the endpoints provided by the IEndpointResolver + /// returned by the EndpointResolverFactory. By default the configured + /// hostname and port are used. + /// + /// + /// When the configured hostname was not reachable. + /// + public IConnection CreateConnection() { - throw new BrokerUnreachableException(e); + return CreateConnection(ClientProvidedName); } - } - - private ConnectionConfig CreateConfig(string clientProvidedName) - { - return new ConnectionConfig( - VirtualHost, - UserName, - Password, - AuthMechanisms, - ClientProperties, - clientProvidedName, - RequestedChannelMax, - RequestedFrameMax, - TopologyRecoveryEnabled, - NetworkRecoveryInterval, - RequestedHeartbeat, - ContinuationTimeout, - HandshakeContinuationTimeout, - RequestedConnectionTimeout, - DispatchConsumersAsync, - ConsumerDispatchConcurrency, - CreateFrameHandler); - } - - internal IFrameHandler CreateFrameHandler(AmqpTcpEndpoint endpoint) - { - IFrameHandler fh = new SocketFrameHandler(endpoint, SocketFactory, RequestedConnectionTimeout, SocketReadTimeout, SocketWriteTimeout); - return ConfigureFrameHandler(fh); - } - private IFrameHandler ConfigureFrameHandler(IFrameHandler fh) - { - // TODO: add user-provided configurator, like in the Java client - fh.ReadTimeout = RequestedHeartbeat; - fh.WriteTimeout = RequestedHeartbeat; - - if (SocketReadTimeout > RequestedHeartbeat) + /// + /// Create a connection to one of the endpoints provided by the IEndpointResolver + /// returned by the EndpointResolverFactory. By default the configured + /// hostname and port are used. + /// + /// + /// Application-specific connection name, will be displayed in the management UI + /// if RabbitMQ server supports it. This value doesn't have to be unique and cannot + /// be used as a connection identifier, e.g. in HTTP API requests. + /// This value is supposed to be human-readable. + /// + /// + /// When the configured hostname was not reachable. + /// + public IConnection CreateConnection(string clientProvidedName) { - fh.ReadTimeout = SocketReadTimeout; + return CreateConnection(EndpointResolverFactory(LocalEndpoints()), clientProvidedName); } - if (SocketWriteTimeout > RequestedHeartbeat) + /// + /// Create a connection using a list of hostnames using the configured port. + /// By default each hostname is tried in a random order until a successful connection is + /// found or the list is exhausted using the DefaultEndpointResolver. + /// The selection behaviour can be overridden by configuring the EndpointResolverFactory. + /// + /// + /// List of hostnames to use for the initial + /// connection and recovery. + /// + /// Open connection + /// + /// When no hostname was reachable. + /// + public IConnection CreateConnection(IList hostnames) { - fh.WriteTimeout = SocketWriteTimeout; + return CreateConnection(hostnames, ClientProvidedName); } - return fh; - } - - private void SetUri(Uri uri) - { - Endpoint = new AmqpTcpEndpoint(); + /// + /// Create a connection using a list of hostnames using the configured port. + /// By default each endpoint is tried in a random order until a successful connection is + /// found or the list is exhausted. + /// The selection behaviour can be overridden by configuring the EndpointResolverFactory. + /// + /// + /// List of hostnames to use for the initial + /// connection and recovery. + /// + /// + /// Application-specific connection name, will be displayed in the management UI + /// if RabbitMQ server supports it. This value doesn't have to be unique and cannot + /// be used as a connection identifier, e.g. in HTTP API requests. + /// This value is supposed to be human-readable. + /// + /// Open connection + /// + /// When no hostname was reachable. + /// + public IConnection CreateConnection(IList hostnames, string clientProvidedName) + { + IEnumerable endpoints = hostnames.Select(h => new AmqpTcpEndpoint(h, Port, Ssl)); + return CreateConnection(EndpointResolverFactory(endpoints), clientProvidedName); + } - if (string.Equals("amqp", uri.Scheme, StringComparison.OrdinalIgnoreCase)) + /// + /// Create a connection using a list of endpoints. By default each endpoint will be tried + /// in a random order until a successful connection is found or the list is exhausted. + /// The selection behaviour can be overridden by configuring the EndpointResolverFactory. + /// + /// + /// List of endpoints to use for the initial + /// connection and recovery. + /// + /// Open connection + /// + /// When no hostname was reachable. + /// + public IConnection CreateConnection(IList endpoints) { - // nothing special to do + return CreateConnection(endpoints, ClientProvidedName); } - else if (string.Equals("amqps", uri.Scheme, StringComparison.OrdinalIgnoreCase)) + + /// + /// Create a connection using a list of endpoints. By default each endpoint will be tried + /// in a random order until a successful connection is found or the list is exhausted. + /// The selection behaviour can be overridden by configuring the EndpointResolverFactory. + /// + /// + /// List of endpoints to use for the initial + /// connection and recovery. + /// + /// + /// Application-specific connection name, will be displayed in the management UI + /// if RabbitMQ server supports it. This value doesn't have to be unique and cannot + /// be used as a connection identifier, e.g. in HTTP API requests. + /// This value is supposed to be human-readable. + /// + /// Open connection + /// + /// When no hostname was reachable. + /// + public IConnection CreateConnection(IList endpoints, string clientProvidedName) { - Ssl.Enabled = true; - Ssl.Version = AmqpUriSslProtocols; - Ssl.AcceptablePolicyErrors = SslPolicyErrors.RemoteCertificateNameMismatch; - Port = AmqpTcpEndpoint.DefaultAmqpSslPort; + return CreateConnection(EndpointResolverFactory(endpoints), clientProvidedName); } - else + + /// + /// Create a connection using an IEndpointResolver. + /// + /// + /// The endpointResolver that returns the endpoints to use for the connection attempt. + /// + /// + /// Application-specific connection name, will be displayed in the management UI + /// if RabbitMQ server supports it. This value doesn't have to be unique and cannot + /// be used as a connection identifier, e.g. in HTTP API requests. + /// This value is supposed to be human-readable. + /// + /// Open connection + /// + /// When no hostname was reachable. + /// + public IConnection CreateConnection(IEndpointResolver endpointResolver, string clientProvidedName) { - throw new ArgumentException($"Wrong scheme in AMQP URI: {uri.Scheme}"); + ConnectionConfig config = CreateConfig(clientProvidedName); + try + { + if (AutomaticRecoveryEnabled) + { + return new AutorecoveringConnection(config, endpointResolver); + } + + return new Connection(config, endpointResolver.SelectOne(CreateFrameHandler)); + } + catch (Exception e) + { + throw new BrokerUnreachableException(e); + } } - string host = uri.Host; - if (!string.IsNullOrEmpty(host)) + + private ConnectionConfig CreateConfig(string clientProvidedName) { - HostName = host; + return new ConnectionConfig( + VirtualHost, + UserName, + Password, + AuthMechanisms, + ClientProperties, + clientProvidedName, + RequestedChannelMax, + RequestedFrameMax, + TopologyRecoveryEnabled, + NetworkRecoveryInterval, + RequestedHeartbeat, + ContinuationTimeout, + HandshakeContinuationTimeout, + RequestedConnectionTimeout, + DispatchConsumersAsync, + ConsumerDispatchConcurrency, + CreateFrameHandler); } - Ssl.ServerName = HostName; - int port = uri.Port; - if (port != -1) + internal IFrameHandler CreateFrameHandler(AmqpTcpEndpoint endpoint) { - Port = port; + IFrameHandler fh = new SocketFrameHandler(endpoint, SocketFactory, RequestedConnectionTimeout, SocketReadTimeout, SocketWriteTimeout); + return ConfigureFrameHandler(fh); } - string userInfo = uri.UserInfo; - if (!string.IsNullOrEmpty(userInfo)) + private IFrameHandler ConfigureFrameHandler(IFrameHandler fh) { - string[] userPass = userInfo.Split(':'); - if (userPass.Length > 2) + // TODO: add user-provided configurator, like in the Java client + fh.ReadTimeout = RequestedHeartbeat; + fh.WriteTimeout = RequestedHeartbeat; + + if (SocketReadTimeout > RequestedHeartbeat) { - throw new ArgumentException($"Bad user info in AMQP URI: {userInfo}"); + fh.ReadTimeout = SocketReadTimeout; } - UserName = UriDecode(userPass[0]); - if (userPass.Length == 2) + + if (SocketWriteTimeout > RequestedHeartbeat) { - Password = UriDecode(userPass[1]); + fh.WriteTimeout = SocketWriteTimeout; } + + return fh; } - /* C# automatically changes URIs into a canonical form - that has at least the path segment "/". */ - if (uri.Segments.Length > 2) + private void SetUri(Uri uri) { - throw new ArgumentException($"Multiple segments in path of AMQP URI: {string.Join(", ", uri.Segments)}"); + Endpoint = new AmqpTcpEndpoint(); + + if (string.Equals("amqp", uri.Scheme, StringComparison.OrdinalIgnoreCase)) + { + // nothing special to do + } + else if (string.Equals("amqps", uri.Scheme, StringComparison.OrdinalIgnoreCase)) + { + Ssl.Enabled = true; + Ssl.Version = AmqpUriSslProtocols; + Ssl.AcceptablePolicyErrors = SslPolicyErrors.RemoteCertificateNameMismatch; + Port = AmqpTcpEndpoint.DefaultAmqpSslPort; + } + else + { + throw new ArgumentException($"Wrong scheme in AMQP URI: {uri.Scheme}"); + } + string host = uri.Host; + if (!string.IsNullOrEmpty(host)) + { + HostName = host; + } + Ssl.ServerName = HostName; + + int port = uri.Port; + if (port != -1) + { + Port = port; + } + + string userInfo = uri.UserInfo; + if (!string.IsNullOrEmpty(userInfo)) + { + string[] userPass = userInfo.Split(':'); + if (userPass.Length > 2) + { + throw new ArgumentException($"Bad user info in AMQP URI: {userInfo}"); + } + UserName = UriDecode(userPass[0]); + if (userPass.Length == 2) + { + Password = UriDecode(userPass[1]); + } + } + + /* C# automatically changes URIs into a canonical form + that has at least the path segment "/". */ + if (uri.Segments.Length > 2) + { + throw new ArgumentException($"Multiple segments in path of AMQP URI: {string.Join(", ", uri.Segments)}"); + } + if (uri.Segments.Length == 2) + { + VirtualHost = UriDecode(uri.Segments[1]); + } + + _uri = uri; } - if (uri.Segments.Length == 2) + + /// + /// Unescape a string, protecting '+'. + /// + private static string UriDecode(string uri) { - VirtualHost = UriDecode(uri.Segments[1]); + return System.Uri.UnescapeDataString(uri.Replace("+", "%2B")); } - _uri = uri; - } - - /// - /// Unescape a string, protecting '+'. - /// - private static string UriDecode(string uri) - { - return System.Uri.UnescapeDataString(uri.Replace("+", "%2B")); - } - - private List LocalEndpoints() - { - return new List { Endpoint }; + private List LocalEndpoints() + { + return new List { Endpoint }; + } } } diff --git a/projects/RabbitMQ.Client/client/api/ConnectionFactoryBase.cs b/projects/RabbitMQ.Client/client/api/ConnectionFactoryBase.cs index dd56f4e300..4964b8f867 100644 --- a/projects/RabbitMQ.Client/client/api/ConnectionFactoryBase.cs +++ b/projects/RabbitMQ.Client/client/api/ConnectionFactoryBase.cs @@ -33,28 +33,29 @@ using System.Net.Sockets; using RabbitMQ.Client.Impl; -namespace RabbitMQ.Client; - -public class ConnectionFactoryBase +namespace RabbitMQ.Client { - /// - /// Set custom socket options by providing a SocketFactory. - /// - public Func SocketFactory = DefaultSocketFactory; - - /// - /// Creates a new instance of the . - /// - /// Specifies the addressing scheme. - /// New instance of a . - public static ITcpClient DefaultSocketFactory(AddressFamily addressFamily) + public class ConnectionFactoryBase { - var socket = new Socket(addressFamily, SocketType.Stream, ProtocolType.Tcp) + /// + /// Set custom socket options by providing a SocketFactory. + /// + public Func SocketFactory = DefaultSocketFactory; + + /// + /// Creates a new instance of the . + /// + /// Specifies the addressing scheme. + /// New instance of a . + public static ITcpClient DefaultSocketFactory(AddressFamily addressFamily) { - NoDelay = true, - ReceiveBufferSize = 65536, - SendBufferSize = 65536 - }; - return new TcpClientAdapter(socket); + var socket = new Socket(addressFamily, SocketType.Stream, ProtocolType.Tcp) + { + NoDelay = true, + ReceiveBufferSize = 65536, + SendBufferSize = 65536 + }; + return new TcpClientAdapter(socket); + } } } diff --git a/projects/RabbitMQ.Client/client/api/DefaultBasicConsumer.cs b/projects/RabbitMQ.Client/client/api/DefaultBasicConsumer.cs index da53eaeefd..9e1b92beb0 100644 --- a/projects/RabbitMQ.Client/client/api/DefaultBasicConsumer.cs +++ b/projects/RabbitMQ.Client/client/api/DefaultBasicConsumer.cs @@ -35,158 +35,159 @@ using RabbitMQ.Client.Events; using RabbitMQ.Client.Impl; -namespace RabbitMQ.Client; - -/// -/// Useful default/base implementation of . -/// Subclass and override in application code. -/// -/// -/// Note that the "Handle*" methods run in the connection's thread! -/// Consider using , which exposes -/// events that can be subscribed to consumer messages. -/// -public class DefaultBasicConsumer : IBasicConsumer +namespace RabbitMQ.Client { - private readonly HashSet _consumerTags = new HashSet(); - /// - /// Creates a new instance of an . + /// Useful default/base implementation of . + /// Subclass and override in application code. /// - public DefaultBasicConsumer() - { - } - - /// - /// Constructor which sets the Model property to the given value. - /// - /// Common AMQP model. - public DefaultBasicConsumer(IModel model) + /// + /// Note that the "Handle*" methods run in the connection's thread! + /// Consider using , which exposes + /// events that can be subscribed to consumer messages. + /// + public class DefaultBasicConsumer : IBasicConsumer { - Model = model; - } + private readonly HashSet _consumerTags = new HashSet(); - /// - /// Retrieve the consumer tags this consumer is registered as; to be used to identify - /// this consumer, for example, when cancelling it with . - /// This value is an array because a single consumer instance can be reused to consume on - /// multiple channels. - /// - public string[] ConsumerTags - { - get + /// + /// Creates a new instance of an . + /// + public DefaultBasicConsumer() { - return _consumerTags.ToArray(); } - } - /// - /// Returns true while the consumer is registered and expecting deliveries from the broker. - /// - public bool IsRunning { get; protected set; } - - /// - /// If our shuts down, this property will contain a description of the reason for the - /// shutdown. Otherwise it will contain null. See . - /// - public ShutdownEventArgs ShutdownReason { get; protected set; } - - /// - /// Signalled when the consumer gets cancelled. - /// - public event EventHandler ConsumerCancelled - { - add => _consumerCancelledWrapper.AddHandler(value); - remove => _consumerCancelledWrapper.RemoveHandler(value); - } - private EventingWrapper _consumerCancelledWrapper; - - /// - /// Retrieve the this consumer is associated with, - /// for use in acknowledging received messages, for instance. - /// - public IModel Model { get; set; } + /// + /// Constructor which sets the Model property to the given value. + /// + /// Common AMQP model. + public DefaultBasicConsumer(IModel model) + { + Model = model; + } - /// - /// Called when the consumer is cancelled for reasons other than by a basicCancel: - /// e.g. the queue has been deleted (either by this channel or by any other channel). - /// See for notification of consumer cancellation due to basicCancel - /// - /// Consumer tag this consumer is registered. - public virtual void HandleBasicCancel(string consumerTag) - { - OnCancel(consumerTag); - } + /// + /// Retrieve the consumer tags this consumer is registered as; to be used to identify + /// this consumer, for example, when cancelling it with . + /// This value is an array because a single consumer instance can be reused to consume on + /// multiple channels. + /// + public string[] ConsumerTags + { + get + { + return _consumerTags.ToArray(); + } + } - /// - /// Called upon successful deregistration of the consumer from the broker. - /// - /// Consumer tag this consumer is registered. - public virtual void HandleBasicCancelOk(string consumerTag) - { - OnCancel(consumerTag); - } + /// + /// Returns true while the consumer is registered and expecting deliveries from the broker. + /// + public bool IsRunning { get; protected set; } + + /// + /// If our shuts down, this property will contain a description of the reason for the + /// shutdown. Otherwise it will contain null. See . + /// + public ShutdownEventArgs ShutdownReason { get; protected set; } + + /// + /// Signalled when the consumer gets cancelled. + /// + public event EventHandler ConsumerCancelled + { + add => _consumerCancelledWrapper.AddHandler(value); + remove => _consumerCancelledWrapper.RemoveHandler(value); + } + private EventingWrapper _consumerCancelledWrapper; + + /// + /// Retrieve the this consumer is associated with, + /// for use in acknowledging received messages, for instance. + /// + public IModel Model { get; set; } + + /// + /// Called when the consumer is cancelled for reasons other than by a basicCancel: + /// e.g. the queue has been deleted (either by this channel or by any other channel). + /// See for notification of consumer cancellation due to basicCancel + /// + /// Consumer tag this consumer is registered. + public virtual void HandleBasicCancel(string consumerTag) + { + OnCancel(consumerTag); + } - /// - /// Called upon successful registration of the consumer with the broker. - /// - /// Consumer tag this consumer is registered. - public virtual void HandleBasicConsumeOk(string consumerTag) - { - _consumerTags.Add(consumerTag); - IsRunning = true; - } + /// + /// Called upon successful deregistration of the consumer from the broker. + /// + /// Consumer tag this consumer is registered. + public virtual void HandleBasicCancelOk(string consumerTag) + { + OnCancel(consumerTag); + } - /// - /// Called each time a message is delivered for this consumer. - /// - /// - /// This is a no-op implementation. It will not acknowledge deliveries via - /// if consuming in automatic acknowledgement mode. - /// Subclasses must copy or fully use delivery body before returning. - /// Accessing the body at a later point is unsafe as its memory can - /// be already released. - /// - public virtual void HandleBasicDeliver(string consumerTag, - ulong deliveryTag, - bool redelivered, - string exchange, - string routingKey, - in ReadOnlyBasicProperties properties, - ReadOnlyMemory body) - { - // Nothing to do here. - } + /// + /// Called upon successful registration of the consumer with the broker. + /// + /// Consumer tag this consumer is registered. + public virtual void HandleBasicConsumeOk(string consumerTag) + { + _consumerTags.Add(consumerTag); + IsRunning = true; + } - /// - /// Called when the model (channel) this consumer was registered on terminates. - /// - /// A channel this consumer was registered on. - /// Shutdown context. - public virtual void HandleModelShutdown(object model, ShutdownEventArgs reason) - { - ShutdownReason = reason; - OnCancel(_consumerTags.ToArray()); - } + /// + /// Called each time a message is delivered for this consumer. + /// + /// + /// This is a no-op implementation. It will not acknowledge deliveries via + /// if consuming in automatic acknowledgement mode. + /// Subclasses must copy or fully use delivery body before returning. + /// Accessing the body at a later point is unsafe as its memory can + /// be already released. + /// + public virtual void HandleBasicDeliver(string consumerTag, + ulong deliveryTag, + bool redelivered, + string exchange, + string routingKey, + in ReadOnlyBasicProperties properties, + ReadOnlyMemory body) + { + // Nothing to do here. + } - /// - /// Default implementation - overridable in subclasses. - /// The set of consumer tags that where cancelled - /// - /// This default implementation simply sets the - /// property to false, and takes no further action. - /// - public virtual void OnCancel(params string[] consumerTags) - { - IsRunning = false; - if (!_consumerCancelledWrapper.IsEmpty) + /// + /// Called when the model (channel) this consumer was registered on terminates. + /// + /// A channel this consumer was registered on. + /// Shutdown context. + public virtual void HandleModelShutdown(object model, ShutdownEventArgs reason) { - _consumerCancelledWrapper.Invoke(this, new ConsumerEventArgs(consumerTags)); + ShutdownReason = reason; + OnCancel(_consumerTags.ToArray()); } - foreach (string consumerTag in consumerTags) + /// + /// Default implementation - overridable in subclasses. + /// The set of consumer tags that where cancelled + /// + /// This default implementation simply sets the + /// property to false, and takes no further action. + /// + public virtual void OnCancel(params string[] consumerTags) { - _consumerTags.Remove(consumerTag); + IsRunning = false; + if (!_consumerCancelledWrapper.IsEmpty) + { + _consumerCancelledWrapper.Invoke(this, new ConsumerEventArgs(consumerTags)); + } + + foreach (string consumerTag in consumerTags) + { + _consumerTags.Remove(consumerTag); + } } } } diff --git a/projects/RabbitMQ.Client/client/api/DefaultEndpointResolver.cs b/projects/RabbitMQ.Client/client/api/DefaultEndpointResolver.cs index fad8f7f224..5d0cbfefc9 100644 --- a/projects/RabbitMQ.Client/client/api/DefaultEndpointResolver.cs +++ b/projects/RabbitMQ.Client/client/api/DefaultEndpointResolver.cs @@ -33,24 +33,25 @@ using System.Collections.Generic; using System.Linq; -namespace RabbitMQ.Client; - -public class DefaultEndpointResolver : IEndpointResolver +namespace RabbitMQ.Client { - private readonly List _endpoints; - private readonly Random _rnd = new Random(); - - public DefaultEndpointResolver(IEnumerable tcpEndpoints) + public class DefaultEndpointResolver : IEndpointResolver { - _endpoints = tcpEndpoints.ToList(); - } + private readonly List _endpoints; + private readonly Random _rnd = new Random(); - public IEnumerable All() - { + public DefaultEndpointResolver(IEnumerable tcpEndpoints) + { + _endpoints = tcpEndpoints.ToList(); + } + + public IEnumerable All() + { #if NET6_0_OR_GREATER return _endpoints.OrderBy(item => Random.Shared.Next()); #else return _endpoints.OrderBy(item => _rnd.Next()); #endif + } } } diff --git a/projects/RabbitMQ.Client/client/api/DeliveryModes.cs b/projects/RabbitMQ.Client/client/api/DeliveryModes.cs index df98e68d70..6dbfb7e9c7 100644 --- a/projects/RabbitMQ.Client/client/api/DeliveryModes.cs +++ b/projects/RabbitMQ.Client/client/api/DeliveryModes.cs @@ -29,20 +29,21 @@ // Copyright (c) 2007-2020 VMware, Inc. All rights reserved. //--------------------------------------------------------------------------- -namespace RabbitMQ.Client; - -/// -/// Convenience enum providing compile-time names for persistent modes. -/// -public enum DeliveryModes : byte +namespace RabbitMQ.Client { /// - /// Value for transient delivery mode (not durable). + /// Convenience enum providing compile-time names for persistent modes. /// - Transient = 1, + public enum DeliveryModes : byte + { + /// + /// Value for transient delivery mode (not durable). + /// + Transient = 1, - /// - /// Value for persistent delivery mode (durable). - /// - Persistent = 2 + /// + /// Value for persistent delivery mode (durable). + /// + Persistent = 2 + } } diff --git a/projects/RabbitMQ.Client/client/api/ExchangeType.cs b/projects/RabbitMQ.Client/client/api/ExchangeType.cs index 3b30413e6c..d861785b09 100644 --- a/projects/RabbitMQ.Client/client/api/ExchangeType.cs +++ b/projects/RabbitMQ.Client/client/api/ExchangeType.cs @@ -31,46 +31,47 @@ using System.Collections.Generic; -namespace RabbitMQ.Client; - -/// -/// Convenience class providing compile-time names for standard exchange types. -/// -/// -/// Use the static members of this class as values for the -/// "exchangeType" arguments for IModel methods such as -/// ExchangeDeclare. The broker may be extended with additional -/// exchange types that do not appear in this class. -/// -public static class ExchangeType +namespace RabbitMQ.Client { /// - /// Exchange type used for AMQP direct exchanges. + /// Convenience class providing compile-time names for standard exchange types. /// - public const string Direct = "direct"; + /// + /// Use the static members of this class as values for the + /// "exchangeType" arguments for IModel methods such as + /// ExchangeDeclare. The broker may be extended with additional + /// exchange types that do not appear in this class. + /// + public static class ExchangeType + { + /// + /// Exchange type used for AMQP direct exchanges. + /// + public const string Direct = "direct"; - /// - /// Exchange type used for AMQP fanout exchanges. - /// - public const string Fanout = "fanout"; + /// + /// Exchange type used for AMQP fanout exchanges. + /// + public const string Fanout = "fanout"; - /// - /// Exchange type used for AMQP headers exchanges. - /// - public const string Headers = "headers"; + /// + /// Exchange type used for AMQP headers exchanges. + /// + public const string Headers = "headers"; - /// - /// Exchange type used for AMQP topic exchanges. - /// - public const string Topic = "topic"; + /// + /// Exchange type used for AMQP topic exchanges. + /// + public const string Topic = "topic"; - private static readonly string[] s_all = { Fanout, Direct, Topic, Headers }; + private static readonly string[] s_all = { Fanout, Direct, Topic, Headers }; - /// - /// Retrieve a collection containing all standard exchange types. - /// - public static ICollection All() - { - return s_all; + /// + /// Retrieve a collection containing all standard exchange types. + /// + public static ICollection All() + { + return s_all; + } } } diff --git a/projects/RabbitMQ.Client/client/api/ExternalMechanism.cs b/projects/RabbitMQ.Client/client/api/ExternalMechanism.cs index 9d5b5c20c6..38b7d243f2 100644 --- a/projects/RabbitMQ.Client/client/api/ExternalMechanism.cs +++ b/projects/RabbitMQ.Client/client/api/ExternalMechanism.cs @@ -31,15 +31,16 @@ using System; -namespace RabbitMQ.Client; - -public class ExternalMechanism : IAuthMechanism +namespace RabbitMQ.Client { - /// - /// Handle one round of challenge-response. - /// - public byte[] handleChallenge(byte[] challenge, ConnectionConfig config) + public class ExternalMechanism : IAuthMechanism { - return Array.Empty(); + /// + /// Handle one round of challenge-response. + /// + public byte[] handleChallenge(byte[] challenge, ConnectionConfig config) + { + return Array.Empty(); + } } } diff --git a/projects/RabbitMQ.Client/client/api/ExternalMechanismFactory.cs b/projects/RabbitMQ.Client/client/api/ExternalMechanismFactory.cs index 43c1081174..ade28631c8 100644 --- a/projects/RabbitMQ.Client/client/api/ExternalMechanismFactory.cs +++ b/projects/RabbitMQ.Client/client/api/ExternalMechanismFactory.cs @@ -29,23 +29,24 @@ // Copyright (c) 2007-2020 VMware, Inc. All rights reserved. //--------------------------------------------------------------------------- -namespace RabbitMQ.Client; - -public class ExternalMechanismFactory : IAuthMechanismFactory +namespace RabbitMQ.Client { - /// - /// The name of the authentication mechanism, as negotiated on the wire. - /// - public string Name + public class ExternalMechanismFactory : IAuthMechanismFactory { - get { return "EXTERNAL"; } - } + /// + /// The name of the authentication mechanism, as negotiated on the wire. + /// + public string Name + { + get { return "EXTERNAL"; } + } - /// - /// Return a new authentication mechanism implementation. - /// - public IAuthMechanism GetInstance() - { - return new ExternalMechanism(); + /// + /// Return a new authentication mechanism implementation. + /// + public IAuthMechanism GetInstance() + { + return new ExternalMechanism(); + } } } diff --git a/projects/RabbitMQ.Client/client/api/Headers.cs b/projects/RabbitMQ.Client/client/api/Headers.cs index 11d6fe2c9c..e7fa505abe 100644 --- a/projects/RabbitMQ.Client/client/api/Headers.cs +++ b/projects/RabbitMQ.Client/client/api/Headers.cs @@ -29,121 +29,122 @@ // Copyright (c) 2007-2020 VMware, Inc. All rights reserved. //--------------------------------------------------------------------------- -namespace RabbitMQ.Client; - -/// -/// Convenience class providing compile-time names for standard headers. -/// -/// -/// Use the static members of this class as headers for the -/// arguments for Queue and Exchange declaration or Consumer creation. -/// The broker may be extended with additional -/// headers that do not appear in this class. -/// -public static class Headers +namespace RabbitMQ.Client { /// - /// x-max-priority header - /// - public const string XMaxPriority = "x-max-priority"; - - /// - /// x-max-length header - /// The max total size in bytes - /// - public const string XMaxLength = "x-max-length"; - - /// - /// x-max-length-bytes header - /// - public const string XMaxLengthInBytes = "x-max-length-bytes"; - - /// - /// x-dead-letter-exchange header - /// - public const string XDeadLetterExchange = "x-dead-letter-exchange"; - - /// - /// x-dead-letter-routing-key header - /// - public const string XDeadLetterRoutingKey = "x-dead-letter-routing-key"; - - /// - /// x-message-ttl header - /// - public const string XMessageTTL = "x-message-ttl"; - - /// - /// x-expires header - /// - public const string XExpires = "x-expires"; - - /// - /// alternate-exchange header - /// - public const string AlternateExchange = "alternate-exchange"; - - /// - /// x-priority header - /// - public const string XPriority = "x-priority"; - - /// - /// x-queue-mode header. - /// Available modes: "default" and "lazy" - /// - public const string XQueueMode = "x-queue-mode"; - - // quorum - /// - /// x-queue-type header. - /// Available types: "quorum" and "classic"(default) and "stream" - /// - public const string XQueueType = "x-queue-type"; - - /// - /// x-quorum-initial-group-size header. - /// Use to control the number of quorum queue members - /// - public const string XQuorumInitialGroupSize = "x-quorum-initial-group-size"; - - // true/false - /// - /// x-single-active-consumer header. - /// Available modes: true and false(default). - /// Allows to have only one consumer at a time consuming from a queue - /// and to fail over to another registered consumer in case the active one is cancelled or dies - /// - public const string XSingleActiveConsumer = "x-single-active-consumer"; - - /// - /// x-overflow header. - /// Available strategies: "reject-publish" and "drop-head"(default). - /// Allows to configure strategy when or hits limits - /// - public const string XOverflow = "x-overflow"; - - /// - /// x-max-age header - /// Sets the maximum age of the stream. Default: not set. - /// valid units: Y, M, D, h, m, s - /// e.g. 7D for a week - /// - public const string XMaxAge = "x-max-age"; - - /// - /// x-stream-max-segment-size-bytes header - /// A stream is divided up into fixed size segment files on disk. - /// This setting controls the size of these. Default: (500000000 bytes). - /// - public const string XStreamMaxSegmentSizeInBytes = "x-stream-max-segment-size-bytes"; - - /// - /// x-stream-offset header. - /// As streams never delete any messages, any consumer can start reading/consuming from any point in the log. - /// this is controlled by the x-stream-offset consumer argument. - /// Available values: "first", "last", "next", Timestamp and Interval (valid units: Y, M, D, h, m, s) - /// See more - /// - public const string XStreamOffset = "x-stream-offset"; + /// Convenience class providing compile-time names for standard headers. + /// + /// + /// Use the static members of this class as headers for the + /// arguments for Queue and Exchange declaration or Consumer creation. + /// The broker may be extended with additional + /// headers that do not appear in this class. + /// + public static class Headers + { + /// + /// x-max-priority header + /// + public const string XMaxPriority = "x-max-priority"; + + /// + /// x-max-length header + /// The max total size in bytes + /// + public const string XMaxLength = "x-max-length"; + + /// + /// x-max-length-bytes header + /// + public const string XMaxLengthInBytes = "x-max-length-bytes"; + + /// + /// x-dead-letter-exchange header + /// + public const string XDeadLetterExchange = "x-dead-letter-exchange"; + + /// + /// x-dead-letter-routing-key header + /// + public const string XDeadLetterRoutingKey = "x-dead-letter-routing-key"; + + /// + /// x-message-ttl header + /// + public const string XMessageTTL = "x-message-ttl"; + + /// + /// x-expires header + /// + public const string XExpires = "x-expires"; + + /// + /// alternate-exchange header + /// + public const string AlternateExchange = "alternate-exchange"; + + /// + /// x-priority header + /// + public const string XPriority = "x-priority"; + + /// + /// x-queue-mode header. + /// Available modes: "default" and "lazy" + /// + public const string XQueueMode = "x-queue-mode"; + + // quorum + /// + /// x-queue-type header. + /// Available types: "quorum" and "classic"(default) and "stream" + /// + public const string XQueueType = "x-queue-type"; + + /// + /// x-quorum-initial-group-size header. + /// Use to control the number of quorum queue members + /// + public const string XQuorumInitialGroupSize = "x-quorum-initial-group-size"; + + // true/false + /// + /// x-single-active-consumer header. + /// Available modes: true and false(default). + /// Allows to have only one consumer at a time consuming from a queue + /// and to fail over to another registered consumer in case the active one is cancelled or dies + /// + public const string XSingleActiveConsumer = "x-single-active-consumer"; + + /// + /// x-overflow header. + /// Available strategies: "reject-publish" and "drop-head"(default). + /// Allows to configure strategy when or hits limits + /// + public const string XOverflow = "x-overflow"; + + /// + /// x-max-age header + /// Sets the maximum age of the stream. Default: not set. + /// valid units: Y, M, D, h, m, s + /// e.g. 7D for a week + /// + public const string XMaxAge = "x-max-age"; + + /// + /// x-stream-max-segment-size-bytes header + /// A stream is divided up into fixed size segment files on disk. + /// This setting controls the size of these. Default: (500000000 bytes). + /// + public const string XStreamMaxSegmentSizeInBytes = "x-stream-max-segment-size-bytes"; + + /// + /// x-stream-offset header. + /// As streams never delete any messages, any consumer can start reading/consuming from any point in the log. + /// this is controlled by the x-stream-offset consumer argument. + /// Available values: "first", "last", "next", Timestamp and Interval (valid units: Y, M, D, h, m, s) + /// See more + /// + public const string XStreamOffset = "x-stream-offset"; + } } diff --git a/projects/RabbitMQ.Client/client/api/IAmqpHeader.cs b/projects/RabbitMQ.Client/client/api/IAmqpHeader.cs index f8953d5b6d..319de11ace 100644 --- a/projects/RabbitMQ.Client/client/api/IAmqpHeader.cs +++ b/projects/RabbitMQ.Client/client/api/IAmqpHeader.cs @@ -29,16 +29,17 @@ // Copyright (c) 2007-2020 VMware, Inc. All rights reserved. //--------------------------------------------------------------------------- -namespace RabbitMQ.Client; - -#nullable enable -/// -/// A AMQP header. -/// -public interface IAmqpHeader : IAmqpWriteable +namespace RabbitMQ.Client { +#nullable enable /// - /// The protocol class id. + /// A AMQP header. /// - ushort ProtocolClassId { get; } + public interface IAmqpHeader : IAmqpWriteable + { + /// + /// The protocol class id. + /// + ushort ProtocolClassId { get; } + } } diff --git a/projects/RabbitMQ.Client/client/api/IAmqpWriteable.cs b/projects/RabbitMQ.Client/client/api/IAmqpWriteable.cs index a8d27230e4..db72f2813b 100644 --- a/projects/RabbitMQ.Client/client/api/IAmqpWriteable.cs +++ b/projects/RabbitMQ.Client/client/api/IAmqpWriteable.cs @@ -31,24 +31,25 @@ using System; -namespace RabbitMQ.Client; - -#nullable enable -/// -/// A AMQP writeable. -/// -public interface IAmqpWriteable +namespace RabbitMQ.Client { +#nullable enable /// - /// Gets the minimum required buffer size. + /// A AMQP writeable. /// - /// The minimum required buffer size. - int GetRequiredBufferSize(); + public interface IAmqpWriteable + { + /// + /// Gets the minimum required buffer size. + /// + /// The minimum required buffer size. + int GetRequiredBufferSize(); - /// - /// Write this instance to the provided span. - /// - /// The span to write it to. - /// The amount of bytes written. - int WriteTo(Span span); + /// + /// Write this instance to the provided span. + /// + /// The span to write it to. + /// The amount of bytes written. + int WriteTo(Span span); + } } diff --git a/projects/RabbitMQ.Client/client/api/IAsyncBasicConsumer.cs b/projects/RabbitMQ.Client/client/api/IAsyncBasicConsumer.cs index 803d56dfd4..24e787d691 100644 --- a/projects/RabbitMQ.Client/client/api/IAsyncBasicConsumer.cs +++ b/projects/RabbitMQ.Client/client/api/IAsyncBasicConsumer.cs @@ -3,61 +3,62 @@ using RabbitMQ.Client.Events; -namespace RabbitMQ.Client; - -public interface IAsyncBasicConsumer +namespace RabbitMQ.Client { - /// - /// Retrieve the this consumer is associated with, - /// for use in acknowledging received messages, for instance. - /// - IModel Model { get; } - - /// - /// Signalled when the consumer gets cancelled. - /// - event AsyncEventHandler ConsumerCancelled; - - /// - /// Called when the consumer is cancelled for reasons other than by a basicCancel: - /// e.g. the queue has been deleted (either by this channel or by any other channel). - /// See for notification of consumer cancellation due to basicCancel - /// - /// Consumer tag this consumer is registered. - Task HandleBasicCancel(string consumerTag); - - /// - /// Called upon successful deregistration of the consumer from the broker. - /// - /// Consumer tag this consumer is registered. - Task HandleBasicCancelOk(string consumerTag); - - /// - /// Called upon successful registration of the consumer with the broker. - /// - /// Consumer tag this consumer is registered. - Task HandleBasicConsumeOk(string consumerTag); - - /// - /// Called each time a message arrives for this consumer. - /// - /// - /// Does nothing with the passed in information. - /// Note that in particular, some delivered messages may require acknowledgement via . - /// The implementation of this method in this class does NOT acknowledge such messages. - /// - Task HandleBasicDeliver(string consumerTag, - ulong deliveryTag, - bool redelivered, - string exchange, - string routingKey, - in ReadOnlyBasicProperties properties, - ReadOnlyMemory body); - - /// - /// Called when the model shuts down. - /// - /// Common AMQP model. - /// Information about the reason why a particular model, session, or connection was destroyed. - Task HandleModelShutdown(object model, ShutdownEventArgs reason); + public interface IAsyncBasicConsumer + { + /// + /// Retrieve the this consumer is associated with, + /// for use in acknowledging received messages, for instance. + /// + IModel Model { get; } + + /// + /// Signalled when the consumer gets cancelled. + /// + event AsyncEventHandler ConsumerCancelled; + + /// + /// Called when the consumer is cancelled for reasons other than by a basicCancel: + /// e.g. the queue has been deleted (either by this channel or by any other channel). + /// See for notification of consumer cancellation due to basicCancel + /// + /// Consumer tag this consumer is registered. + Task HandleBasicCancel(string consumerTag); + + /// + /// Called upon successful deregistration of the consumer from the broker. + /// + /// Consumer tag this consumer is registered. + Task HandleBasicCancelOk(string consumerTag); + + /// + /// Called upon successful registration of the consumer with the broker. + /// + /// Consumer tag this consumer is registered. + Task HandleBasicConsumeOk(string consumerTag); + + /// + /// Called each time a message arrives for this consumer. + /// + /// + /// Does nothing with the passed in information. + /// Note that in particular, some delivered messages may require acknowledgement via . + /// The implementation of this method in this class does NOT acknowledge such messages. + /// + Task HandleBasicDeliver(string consumerTag, + ulong deliveryTag, + bool redelivered, + string exchange, + string routingKey, + in ReadOnlyBasicProperties properties, + ReadOnlyMemory body); + + /// + /// Called when the model shuts down. + /// + /// Common AMQP model. + /// Information about the reason why a particular model, session, or connection was destroyed. + Task HandleModelShutdown(object model, ShutdownEventArgs reason); + } } diff --git a/projects/RabbitMQ.Client/client/api/IAuthMechanism.cs b/projects/RabbitMQ.Client/client/api/IAuthMechanism.cs index 2d3f1fa513..bae25110dd 100644 --- a/projects/RabbitMQ.Client/client/api/IAuthMechanism.cs +++ b/projects/RabbitMQ.Client/client/api/IAuthMechanism.cs @@ -29,15 +29,16 @@ // Copyright (c) 2007-2020 VMware, Inc. All rights reserved. //--------------------------------------------------------------------------- -namespace RabbitMQ.Client; - -/// -/// A pluggable authentication mechanism. -/// -public interface IAuthMechanism +namespace RabbitMQ.Client { /// - /// Handle one round of challenge-response. + /// A pluggable authentication mechanism. /// - byte[] handleChallenge(byte[] challenge, ConnectionConfig config); + public interface IAuthMechanism + { + /// + /// Handle one round of challenge-response. + /// + byte[] handleChallenge(byte[] challenge, ConnectionConfig config); + } } diff --git a/projects/RabbitMQ.Client/client/api/IAuthMechanismFactory.cs b/projects/RabbitMQ.Client/client/api/IAuthMechanismFactory.cs index 53c9fbe90c..2863465193 100644 --- a/projects/RabbitMQ.Client/client/api/IAuthMechanismFactory.cs +++ b/projects/RabbitMQ.Client/client/api/IAuthMechanismFactory.cs @@ -29,17 +29,18 @@ // Copyright (c) 2007-2020 VMware, Inc. All rights reserved. //--------------------------------------------------------------------------- -namespace RabbitMQ.Client; - -public interface IAuthMechanismFactory +namespace RabbitMQ.Client { - /// - /// The name of the authentication mechanism, as negotiated on the wire. - /// - string Name { get; } + public interface IAuthMechanismFactory + { + /// + /// The name of the authentication mechanism, as negotiated on the wire. + /// + string Name { get; } - /// - /// Return a new authentication mechanism implementation. - /// - IAuthMechanism GetInstance(); + /// + /// Return a new authentication mechanism implementation. + /// + IAuthMechanism GetInstance(); + } } diff --git a/projects/RabbitMQ.Client/client/api/IBasicConsumer.cs b/projects/RabbitMQ.Client/client/api/IBasicConsumer.cs index f3ec73a81b..94627c5a35 100644 --- a/projects/RabbitMQ.Client/client/api/IBasicConsumer.cs +++ b/projects/RabbitMQ.Client/client/api/IBasicConsumer.cs @@ -33,74 +33,75 @@ using RabbitMQ.Client.Events; -namespace RabbitMQ.Client; - -/// Consumer interface. Used to -///receive messages from a queue by subscription. -/// -/// -/// See IModel.BasicConsume, IModel.BasicCancel. -/// -/// -/// Note that the "Handle*" methods run in the connection's -/// thread! Consider using , which uses a -/// SharedQueue instance to safely pass received messages across -/// to user threads. -/// -/// -public interface IBasicConsumer +namespace RabbitMQ.Client { - /// - /// Retrieve the this consumer is associated with, - /// for use in acknowledging received messages, for instance. - /// - IModel Model { get; } + /// Consumer interface. Used to + ///receive messages from a queue by subscription. + /// + /// + /// See IModel.BasicConsume, IModel.BasicCancel. + /// + /// + /// Note that the "Handle*" methods run in the connection's + /// thread! Consider using , which uses a + /// SharedQueue instance to safely pass received messages across + /// to user threads. + /// + /// + public interface IBasicConsumer + { + /// + /// Retrieve the this consumer is associated with, + /// for use in acknowledging received messages, for instance. + /// + IModel Model { get; } - /// - /// Signalled when the consumer gets cancelled. - /// - event EventHandler ConsumerCancelled; + /// + /// Signalled when the consumer gets cancelled. + /// + event EventHandler ConsumerCancelled; - /// - /// Called when the consumer is cancelled for reasons other than by a basicCancel: - /// e.g. the queue has been deleted (either by this channel or by any other channel). - /// See for notification of consumer cancellation due to basicCancel - /// - /// Consumer tag this consumer is registered. - void HandleBasicCancel(string consumerTag); + /// + /// Called when the consumer is cancelled for reasons other than by a basicCancel: + /// e.g. the queue has been deleted (either by this channel or by any other channel). + /// See for notification of consumer cancellation due to basicCancel + /// + /// Consumer tag this consumer is registered. + void HandleBasicCancel(string consumerTag); - /// - /// Called upon successful deregistration of the consumer from the broker. - /// - /// Consumer tag this consumer is registered. - void HandleBasicCancelOk(string consumerTag); + /// + /// Called upon successful deregistration of the consumer from the broker. + /// + /// Consumer tag this consumer is registered. + void HandleBasicCancelOk(string consumerTag); - /// - /// Called upon successful registration of the consumer with the broker. - /// - /// Consumer tag this consumer is registered. - void HandleBasicConsumeOk(string consumerTag); + /// + /// Called upon successful registration of the consumer with the broker. + /// + /// Consumer tag this consumer is registered. + void HandleBasicConsumeOk(string consumerTag); - /// - /// Called each time a message arrives for this consumer. - /// - /// - /// Does nothing with the passed in information. - /// Note that in particular, some delivered messages may require acknowledgement via . - /// The implementation of this method in this class does NOT acknowledge such messages. - /// - void HandleBasicDeliver(string consumerTag, - ulong deliveryTag, - bool redelivered, - string exchange, - string routingKey, - in ReadOnlyBasicProperties properties, - ReadOnlyMemory body); + /// + /// Called each time a message arrives for this consumer. + /// + /// + /// Does nothing with the passed in information. + /// Note that in particular, some delivered messages may require acknowledgement via . + /// The implementation of this method in this class does NOT acknowledge such messages. + /// + void HandleBasicDeliver(string consumerTag, + ulong deliveryTag, + bool redelivered, + string exchange, + string routingKey, + in ReadOnlyBasicProperties properties, + ReadOnlyMemory body); - /// - /// Called when the model shuts down. - /// - /// Common AMQP model. - /// Information about the reason why a particular model, session, or connection was destroyed. - void HandleModelShutdown(object model, ShutdownEventArgs reason); + /// + /// Called when the model shuts down. + /// + /// Common AMQP model. + /// Information about the reason why a particular model, session, or connection was destroyed. + void HandleModelShutdown(object model, ShutdownEventArgs reason); + } } diff --git a/projects/RabbitMQ.Client/client/api/IBasicProperties.cs b/projects/RabbitMQ.Client/client/api/IBasicProperties.cs index 4bd5398423..c69670f55c 100644 --- a/projects/RabbitMQ.Client/client/api/IBasicProperties.cs +++ b/projects/RabbitMQ.Client/client/api/IBasicProperties.cs @@ -31,332 +31,333 @@ using System.Collections.Generic; -namespace RabbitMQ.Client; - -#nullable enable -/// -/// The AMQP Basic headers class interface, -/// spanning the union of the functionality offered by versions -/// 0-8, 0-8qpid, 0-9 and 0-9-1 of AMQP. -/// -public interface IReadOnlyBasicProperties +namespace RabbitMQ.Client { +#nullable enable /// - /// Application Id. - /// - string? AppId { get; } - - /// - /// Intra-cluster routing identifier (cluster id is deprecated in AMQP 0-9-1). - /// - string? ClusterId { get; } - - /// - /// MIME content encoding. - /// - string? ContentEncoding { get; } - - /// - /// MIME content type. - /// - string? ContentType { get; } - - /// - /// Application correlation identifier. - /// - string? CorrelationId { get; } - - /// - /// Non-persistent (1) or persistent (2). - /// - DeliveryModes DeliveryMode { get; } - - /// - /// Message expiration specification. - /// - string? Expiration { get; } - - /// - /// Message header field table. Is of type . - /// - IDictionary? Headers { get; } - - /// - /// Application message Id. - /// - string? MessageId { get; } - - /// - /// Sets to either persistent (2) or non-persistent (1). - /// - bool Persistent { get; } - - /// - /// Message priority, 0 to 9. - /// - byte Priority { get; } - - /// - /// Destination to reply to. - /// - string? ReplyTo { get; } - - /// - /// Convenience property; parses property using , - /// and serializes it using . - /// Returns null if property cannot be parsed by . - /// - PublicationAddress? ReplyToAddress { get; } - - /// - /// Message timestamp. - /// - AmqpTimestamp Timestamp { get; } - - /// - /// Message type name. - /// - string? Type { get; } - - /// - /// User Id. - /// - string? UserId { get; } - - /// - /// Returns true if the property is present. - /// - bool IsAppIdPresent(); - - /// - /// Returns true if the property is present (cluster id is deprecated in AMQP 0-9-1). - /// - bool IsClusterIdPresent(); - - /// - /// Returns true if the property is present. - /// - bool IsContentEncodingPresent(); - - /// - /// Returns true if the property is present. - /// - bool IsContentTypePresent(); - - /// - /// Returns true if the property is present. - /// - bool IsCorrelationIdPresent(); - - /// - /// Returns true if the property is present. - /// - bool IsDeliveryModePresent(); - - /// - /// Returns true if the property is present. - /// - bool IsExpirationPresent(); - - /// - /// Returns true if the property is present. - /// - bool IsHeadersPresent(); - - /// - /// Returns true if the property is present. - /// - bool IsMessageIdPresent(); - - /// - /// Returns true if the property is present. - /// - bool IsPriorityPresent(); - - /// - /// Returns true if the property is present. - /// - bool IsReplyToPresent(); - - /// - /// Returns true if the property is present. - /// - bool IsTimestampPresent(); - - /// - /// Returns true if the property is present. - /// - bool IsTypePresent(); - - /// - /// Returns true if the property is present. - /// - bool IsUserIdPresent(); -} - -/// -/// The AMQP Basic headers class interface, -/// spanning the union of the functionality offered by versions -/// 0-8, 0-8qpid, 0-9 and 0-9-1 of AMQP. -/// -/// -/// -/// Each property is readable, writable and clearable: a cleared -/// property will not be transmitted over the wire. Properties on a -/// fresh instance are clear by default. -/// -/// -public interface IBasicProperties : IReadOnlyBasicProperties -{ - /// - /// Application Id. - /// - new string? AppId { get; set; } - - /// - /// Intra-cluster routing identifier (cluster id is deprecated in AMQP 0-9-1). - /// - new string? ClusterId { get; set; } - - /// - /// MIME content encoding. - /// - new string? ContentEncoding { get; set; } - - /// - /// MIME content type. - /// - new string? ContentType { get; set; } - - /// - /// Application correlation identifier. - /// - new string? CorrelationId { get; set; } - - /// - /// Non-persistent (1) or persistent (2). - /// - new DeliveryModes DeliveryMode { get; set; } - - /// - /// Message expiration specification. - /// - new string? Expiration { get; set; } - - /// - /// Message header field table. Is of type . - /// - new IDictionary? Headers { get; set; } - - /// - /// Application message Id. - /// - new string? MessageId { get; set; } - - /// - /// Sets to either persistent (2) or non-persistent (1). - /// - new bool Persistent { get; set; } - - /// - /// Message priority, 0 to 9. - /// - new byte Priority { get; set; } - - /// - /// Destination to reply to. - /// - new string? ReplyTo { get; set; } - - /// - /// Convenience property; parses property using , - /// and serializes it using . - /// Returns null if property cannot be parsed by . - /// - new PublicationAddress? ReplyToAddress { get; set; } - - /// - /// Message timestamp. - /// - new AmqpTimestamp Timestamp { get; set; } - - /// - /// Message type name. - /// - new string? Type { get; set; } - - /// - /// User Id. - /// - new string? UserId { get; set; } - - /// - /// Clear the property. - /// - void ClearAppId(); - - /// - /// Clear the property (cluster id is deprecated in AMQP 0-9-1). - /// - void ClearClusterId(); - - /// - /// Clear the property. - /// - void ClearContentEncoding(); - - /// - /// Clear the property. - /// - void ClearContentType(); - - /// - /// Clear the property. - /// - void ClearCorrelationId(); - - /// - /// Clear the property. - /// - void ClearDeliveryMode(); - - /// - /// Clear the property. - /// - void ClearExpiration(); - - /// - /// Clear the property. - /// - void ClearHeaders(); - - /// - /// Clear the property. - /// - void ClearMessageId(); - - /// - /// Clear the property. - /// - void ClearPriority(); - - /// - /// Clear the property. - /// - void ClearReplyTo(); - - /// - /// Clear the property. - /// - void ClearTimestamp(); - - /// - /// Clear the property. - /// - void ClearType(); - - /// - /// Clear the property. - /// - void ClearUserId(); + /// The AMQP Basic headers class interface, + /// spanning the union of the functionality offered by versions + /// 0-8, 0-8qpid, 0-9 and 0-9-1 of AMQP. + /// + public interface IReadOnlyBasicProperties + { + /// + /// Application Id. + /// + string? AppId { get; } + + /// + /// Intra-cluster routing identifier (cluster id is deprecated in AMQP 0-9-1). + /// + string? ClusterId { get; } + + /// + /// MIME content encoding. + /// + string? ContentEncoding { get; } + + /// + /// MIME content type. + /// + string? ContentType { get; } + + /// + /// Application correlation identifier. + /// + string? CorrelationId { get; } + + /// + /// Non-persistent (1) or persistent (2). + /// + DeliveryModes DeliveryMode { get; } + + /// + /// Message expiration specification. + /// + string? Expiration { get; } + + /// + /// Message header field table. Is of type . + /// + IDictionary? Headers { get; } + + /// + /// Application message Id. + /// + string? MessageId { get; } + + /// + /// Sets to either persistent (2) or non-persistent (1). + /// + bool Persistent { get; } + + /// + /// Message priority, 0 to 9. + /// + byte Priority { get; } + + /// + /// Destination to reply to. + /// + string? ReplyTo { get; } + + /// + /// Convenience property; parses property using , + /// and serializes it using . + /// Returns null if property cannot be parsed by . + /// + PublicationAddress? ReplyToAddress { get; } + + /// + /// Message timestamp. + /// + AmqpTimestamp Timestamp { get; } + + /// + /// Message type name. + /// + string? Type { get; } + + /// + /// User Id. + /// + string? UserId { get; } + + /// + /// Returns true if the property is present. + /// + bool IsAppIdPresent(); + + /// + /// Returns true if the property is present (cluster id is deprecated in AMQP 0-9-1). + /// + bool IsClusterIdPresent(); + + /// + /// Returns true if the property is present. + /// + bool IsContentEncodingPresent(); + + /// + /// Returns true if the property is present. + /// + bool IsContentTypePresent(); + + /// + /// Returns true if the property is present. + /// + bool IsCorrelationIdPresent(); + + /// + /// Returns true if the property is present. + /// + bool IsDeliveryModePresent(); + + /// + /// Returns true if the property is present. + /// + bool IsExpirationPresent(); + + /// + /// Returns true if the property is present. + /// + bool IsHeadersPresent(); + + /// + /// Returns true if the property is present. + /// + bool IsMessageIdPresent(); + + /// + /// Returns true if the property is present. + /// + bool IsPriorityPresent(); + + /// + /// Returns true if the property is present. + /// + bool IsReplyToPresent(); + + /// + /// Returns true if the property is present. + /// + bool IsTimestampPresent(); + + /// + /// Returns true if the property is present. + /// + bool IsTypePresent(); + + /// + /// Returns true if the property is present. + /// + bool IsUserIdPresent(); + } + + /// + /// The AMQP Basic headers class interface, + /// spanning the union of the functionality offered by versions + /// 0-8, 0-8qpid, 0-9 and 0-9-1 of AMQP. + /// + /// + /// + /// Each property is readable, writable and clearable: a cleared + /// property will not be transmitted over the wire. Properties on a + /// fresh instance are clear by default. + /// + /// + public interface IBasicProperties : IReadOnlyBasicProperties + { + /// + /// Application Id. + /// + new string? AppId { get; set; } + + /// + /// Intra-cluster routing identifier (cluster id is deprecated in AMQP 0-9-1). + /// + new string? ClusterId { get; set; } + + /// + /// MIME content encoding. + /// + new string? ContentEncoding { get; set; } + + /// + /// MIME content type. + /// + new string? ContentType { get; set; } + + /// + /// Application correlation identifier. + /// + new string? CorrelationId { get; set; } + + /// + /// Non-persistent (1) or persistent (2). + /// + new DeliveryModes DeliveryMode { get; set; } + + /// + /// Message expiration specification. + /// + new string? Expiration { get; set; } + + /// + /// Message header field table. Is of type . + /// + new IDictionary? Headers { get; set; } + + /// + /// Application message Id. + /// + new string? MessageId { get; set; } + + /// + /// Sets to either persistent (2) or non-persistent (1). + /// + new bool Persistent { get; set; } + + /// + /// Message priority, 0 to 9. + /// + new byte Priority { get; set; } + + /// + /// Destination to reply to. + /// + new string? ReplyTo { get; set; } + + /// + /// Convenience property; parses property using , + /// and serializes it using . + /// Returns null if property cannot be parsed by . + /// + new PublicationAddress? ReplyToAddress { get; set; } + + /// + /// Message timestamp. + /// + new AmqpTimestamp Timestamp { get; set; } + + /// + /// Message type name. + /// + new string? Type { get; set; } + + /// + /// User Id. + /// + new string? UserId { get; set; } + + /// + /// Clear the property. + /// + void ClearAppId(); + + /// + /// Clear the property (cluster id is deprecated in AMQP 0-9-1). + /// + void ClearClusterId(); + + /// + /// Clear the property. + /// + void ClearContentEncoding(); + + /// + /// Clear the property. + /// + void ClearContentType(); + + /// + /// Clear the property. + /// + void ClearCorrelationId(); + + /// + /// Clear the property. + /// + void ClearDeliveryMode(); + + /// + /// Clear the property. + /// + void ClearExpiration(); + + /// + /// Clear the property. + /// + void ClearHeaders(); + + /// + /// Clear the property. + /// + void ClearMessageId(); + + /// + /// Clear the property. + /// + void ClearPriority(); + + /// + /// Clear the property. + /// + void ClearReplyTo(); + + /// + /// Clear the property. + /// + void ClearTimestamp(); + + /// + /// Clear the property. + /// + void ClearType(); + + /// + /// Clear the property. + /// + void ClearUserId(); + } } diff --git a/projects/RabbitMQ.Client/client/api/IConnection.cs b/projects/RabbitMQ.Client/client/api/IConnection.cs index 43fc230838..52b022ace7 100644 --- a/projects/RabbitMQ.Client/client/api/IConnection.cs +++ b/projects/RabbitMQ.Client/client/api/IConnection.cs @@ -34,187 +34,188 @@ using RabbitMQ.Client.Events; using RabbitMQ.Client.Exceptions; -namespace RabbitMQ.Client; - -/// -/// Main interface to an AMQP connection. -/// -/// -/// -/// Instances of are used to create fresh -/// sessions/channels. The class is used to -/// construct instances. -/// Please see the documentation for ConnectionFactory for an example of usage. -/// Alternatively, an API tutorial can be found in the User Guide. -/// -/// -/// Extends the interface, so that the "using" -/// statement can be used to scope the lifetime of a connection when -/// appropriate. -/// -/// -public interface IConnection : INetworkConnection, IDisposable +namespace RabbitMQ.Client { /// - /// The maximum channel number this connection supports (0 if unlimited). - /// Usable channel numbers range from 1 to this number, inclusive. - /// - ushort ChannelMax { get; } - - /// - /// A copy of the client properties that has been sent to the server. - /// - IDictionary ClientProperties { get; } - - /// - /// Returns null if the connection is still in a state - /// where it can be used, or the cause of its closure otherwise. + /// Main interface to an AMQP connection. /// /// /// - /// Applications should use the ConnectionShutdown event to - /// avoid race conditions. The scenario to avoid is checking - /// , seeing it is null (meaning the - /// was available for use at the time of the check), and - /// interpreting this mistakenly as a guarantee that the - /// will remain usable for a time. Instead, the - /// operation of interest should simply be attempted: if the - /// is not in a usable state, an exception will be - /// thrown (most likely , but may - /// vary depending on the particular operation being attempted). + /// Instances of are used to create fresh + /// sessions/channels. The class is used to + /// construct instances. + /// Please see the documentation for ConnectionFactory for an example of usage. + /// Alternatively, an API tutorial can be found in the User Guide. + /// + /// + /// Extends the interface, so that the "using" + /// statement can be used to scope the lifetime of a connection when + /// appropriate. /// /// - ShutdownEventArgs CloseReason { get; } - - /// - /// Retrieve the endpoint this connection is connected to. - /// - AmqpTcpEndpoint Endpoint { get; } - - /// - /// The maximum frame size this connection supports (0 if unlimited). - /// - uint FrameMax { get; } - - /// - /// The current heartbeat setting for this connection (System.TimeSpan.Zero for disabled). - /// - TimeSpan Heartbeat { get; } - - /// - /// Returns true if the connection is still in a state where it can be used. - /// Identical to checking if equal null. - /// - bool IsOpen { get; } - - /// - /// The this connection is using to communicate with its peer. - /// - IProtocol Protocol { get; } - - /// - /// A dictionary of the server properties sent by the server while establishing the connection. - /// This typically includes the product name and version of the server. - /// - IDictionary ServerProperties { get; } - - /// - /// Returns the list of objects that contain information - /// about any errors reported while closing the connection in the order they appeared - /// - IList ShutdownReport { get; } - - /// - /// Application-specific connection name, will be displayed in the management UI - /// if RabbitMQ server supports it. This value doesn't have to be unique and cannot - /// be used as a connection identifier, e.g. in HTTP API requests. - /// This value is supposed to be human-readable. - /// - string ClientProvidedName { get; } - - /// - /// Signalled when an exception occurs in a callback invoked by the connection. - /// - /// - /// This event is signalled when a ConnectionShutdown handler - /// throws an exception. If, in future, more events appear on - /// , then this event will be signalled whenever one - /// of those event handlers throws an exception, as well. - /// - event EventHandler CallbackException; - - event EventHandler ConnectionBlocked; - - /// - /// Raised when the connection is destroyed. - /// - /// - /// If the connection is already destroyed at the time an - /// event handler is added to this event, the event handler - /// will be fired immediately. - /// - event EventHandler ConnectionShutdown; - - /// - /// Raised when the connection completes recovery. - /// - /// - /// This event will never fire for connections that disable automatic recovery. - /// - event EventHandler RecoverySucceeded; - - /// - /// Raised when the connection recovery fails, e.g. because reconnection or topology - /// recovery failed. - /// - /// - /// This event will never fire for connections that disable automatic recovery. - /// - event EventHandler ConnectionRecoveryError; - - /// - /// Raised when the server-generated tag of a consumer registered on this connection changes during - /// connection recovery. This allows applications that need to be aware of server-generated - /// consumer tag values to keep track of the changes. - /// - /// - /// This event will never fire for connections that disable automatic recovery. - /// - event EventHandler ConsumerTagChangeAfterRecovery; - - /// - /// Raised when the name of a server-named queue declared on this connection changes during - /// connection recovery. This allows applications that need to be aware of server-named - /// queue names to keep track of the changes. - /// - /// - /// This event will never fire for connections that disable automatic recovery. - /// - event EventHandler QueueNameChangeAfterRecovery; - - event EventHandler ConnectionUnblocked; - - /// - /// This method updates the secret used to authenticate this connection. - /// It is used when secrets have an expiration date and need to be renewed, - /// like OAuth 2 tokens. - /// - /// The new secret. - /// The reason for the secret update. - void UpdateSecret(string newSecret, string reason); - - /// - /// Close this connection and all its channels - /// and wait with a timeout for all the in-progress close operations to complete. - /// - /// The close code (See under "Reply Codes" in the AMQP 0-9-1 specification). - /// A message indicating the reason for closing the connection. - /// Operation timeout. - /// Whether or not this close is an abort (ignores certain exceptions). - void Close(ushort reasonCode, string reasonText, TimeSpan timeout, bool abort); - - /// - /// Create and return a fresh channel, session, and model. - /// - IModel CreateModel(); + public interface IConnection : INetworkConnection, IDisposable + { + /// + /// The maximum channel number this connection supports (0 if unlimited). + /// Usable channel numbers range from 1 to this number, inclusive. + /// + ushort ChannelMax { get; } + + /// + /// A copy of the client properties that has been sent to the server. + /// + IDictionary ClientProperties { get; } + + /// + /// Returns null if the connection is still in a state + /// where it can be used, or the cause of its closure otherwise. + /// + /// + /// + /// Applications should use the ConnectionShutdown event to + /// avoid race conditions. The scenario to avoid is checking + /// , seeing it is null (meaning the + /// was available for use at the time of the check), and + /// interpreting this mistakenly as a guarantee that the + /// will remain usable for a time. Instead, the + /// operation of interest should simply be attempted: if the + /// is not in a usable state, an exception will be + /// thrown (most likely , but may + /// vary depending on the particular operation being attempted). + /// + /// + ShutdownEventArgs CloseReason { get; } + + /// + /// Retrieve the endpoint this connection is connected to. + /// + AmqpTcpEndpoint Endpoint { get; } + + /// + /// The maximum frame size this connection supports (0 if unlimited). + /// + uint FrameMax { get; } + + /// + /// The current heartbeat setting for this connection (System.TimeSpan.Zero for disabled). + /// + TimeSpan Heartbeat { get; } + + /// + /// Returns true if the connection is still in a state where it can be used. + /// Identical to checking if equal null. + /// + bool IsOpen { get; } + + /// + /// The this connection is using to communicate with its peer. + /// + IProtocol Protocol { get; } + + /// + /// A dictionary of the server properties sent by the server while establishing the connection. + /// This typically includes the product name and version of the server. + /// + IDictionary ServerProperties { get; } + + /// + /// Returns the list of objects that contain information + /// about any errors reported while closing the connection in the order they appeared + /// + IList ShutdownReport { get; } + + /// + /// Application-specific connection name, will be displayed in the management UI + /// if RabbitMQ server supports it. This value doesn't have to be unique and cannot + /// be used as a connection identifier, e.g. in HTTP API requests. + /// This value is supposed to be human-readable. + /// + string ClientProvidedName { get; } + + /// + /// Signalled when an exception occurs in a callback invoked by the connection. + /// + /// + /// This event is signalled when a ConnectionShutdown handler + /// throws an exception. If, in future, more events appear on + /// , then this event will be signalled whenever one + /// of those event handlers throws an exception, as well. + /// + event EventHandler CallbackException; + + event EventHandler ConnectionBlocked; + + /// + /// Raised when the connection is destroyed. + /// + /// + /// If the connection is already destroyed at the time an + /// event handler is added to this event, the event handler + /// will be fired immediately. + /// + event EventHandler ConnectionShutdown; + + /// + /// Raised when the connection completes recovery. + /// + /// + /// This event will never fire for connections that disable automatic recovery. + /// + event EventHandler RecoverySucceeded; + + /// + /// Raised when the connection recovery fails, e.g. because reconnection or topology + /// recovery failed. + /// + /// + /// This event will never fire for connections that disable automatic recovery. + /// + event EventHandler ConnectionRecoveryError; + + /// + /// Raised when the server-generated tag of a consumer registered on this connection changes during + /// connection recovery. This allows applications that need to be aware of server-generated + /// consumer tag values to keep track of the changes. + /// + /// + /// This event will never fire for connections that disable automatic recovery. + /// + event EventHandler ConsumerTagChangeAfterRecovery; + + /// + /// Raised when the name of a server-named queue declared on this connection changes during + /// connection recovery. This allows applications that need to be aware of server-named + /// queue names to keep track of the changes. + /// + /// + /// This event will never fire for connections that disable automatic recovery. + /// + event EventHandler QueueNameChangeAfterRecovery; + + event EventHandler ConnectionUnblocked; + + /// + /// This method updates the secret used to authenticate this connection. + /// It is used when secrets have an expiration date and need to be renewed, + /// like OAuth 2 tokens. + /// + /// The new secret. + /// The reason for the secret update. + void UpdateSecret(string newSecret, string reason); + + /// + /// Close this connection and all its channels + /// and wait with a timeout for all the in-progress close operations to complete. + /// + /// The close code (See under "Reply Codes" in the AMQP 0-9-1 specification). + /// A message indicating the reason for closing the connection. + /// Operation timeout. + /// Whether or not this close is an abort (ignores certain exceptions). + void Close(ushort reasonCode, string reasonText, TimeSpan timeout, bool abort); + + /// + /// Create and return a fresh channel, session, and model. + /// + IModel CreateModel(); + } } diff --git a/projects/RabbitMQ.Client/client/api/IConnectionExtensions.cs b/projects/RabbitMQ.Client/client/api/IConnectionExtensions.cs index 7f1dee29cc..444b46c70a 100644 --- a/projects/RabbitMQ.Client/client/api/IConnectionExtensions.cs +++ b/projects/RabbitMQ.Client/client/api/IConnectionExtensions.cs @@ -2,152 +2,153 @@ using System.IO; using System.Threading; -namespace RabbitMQ.Client; - -public static class IConnectionExtensions +namespace RabbitMQ.Client { - /// - /// Close this connection and all its channels. - /// - /// - /// Note that all active channels, sessions, and models will be - /// closed if this method is called. It will wait for the in-progress - /// close operation to complete. This method will not return to the caller - /// until the shutdown is complete. If the connection is already closed - /// (or closing), then this method will do nothing. - /// It can also throw when socket was closed unexpectedly. - /// - public static void Close(this IConnection connection) + public static class IConnectionExtensions { - connection.Close(Constants.ReplySuccess, "Goodbye", InternalConstants.DefaultConnectionCloseTimeout, false); - } + /// + /// Close this connection and all its channels. + /// + /// + /// Note that all active channels, sessions, and models will be + /// closed if this method is called. It will wait for the in-progress + /// close operation to complete. This method will not return to the caller + /// until the shutdown is complete. If the connection is already closed + /// (or closing), then this method will do nothing. + /// It can also throw when socket was closed unexpectedly. + /// + public static void Close(this IConnection connection) + { + connection.Close(Constants.ReplySuccess, "Goodbye", InternalConstants.DefaultConnectionCloseTimeout, false); + } - /// - /// Close this connection and all its channels. - /// - /// - /// The method behaves in the same way as , with the only - /// difference that the connection is closed with the given connection close code and message. - /// - /// The close code (See under "Reply Codes" in the AMQP specification). - /// - /// - /// A message indicating the reason for closing the connection. - /// - /// - public static void Close(this IConnection connection, ushort reasonCode, string reasonText) - { - connection.Close(reasonCode, reasonText, InternalConstants.DefaultConnectionCloseTimeout, false); - } + /// + /// Close this connection and all its channels. + /// + /// + /// The method behaves in the same way as , with the only + /// difference that the connection is closed with the given connection close code and message. + /// + /// The close code (See under "Reply Codes" in the AMQP specification). + /// + /// + /// A message indicating the reason for closing the connection. + /// + /// + public static void Close(this IConnection connection, ushort reasonCode, string reasonText) + { + connection.Close(reasonCode, reasonText, InternalConstants.DefaultConnectionCloseTimeout, false); + } - /// - /// Close this connection and all its channels - /// and wait with a timeout for all the in-progress close operations to complete. - /// - /// - /// Note that all active channels, sessions, and models will be - /// closed if this method is called. It will wait for the in-progress - /// close operation to complete with a timeout. If the connection is - /// already closed (or closing), then this method will do nothing. - /// It can also throw when socket was closed unexpectedly. - /// If timeout is reached and the close operations haven't finished, then socket is forced to close. - /// - /// To wait infinitely for the close operations to complete use . - /// - /// - public static void Close(this IConnection connection, TimeSpan timeout) - { - connection.Close(Constants.ReplySuccess, "Goodbye", timeout, false); - } + /// + /// Close this connection and all its channels + /// and wait with a timeout for all the in-progress close operations to complete. + /// + /// + /// Note that all active channels, sessions, and models will be + /// closed if this method is called. It will wait for the in-progress + /// close operation to complete with a timeout. If the connection is + /// already closed (or closing), then this method will do nothing. + /// It can also throw when socket was closed unexpectedly. + /// If timeout is reached and the close operations haven't finished, then socket is forced to close. + /// + /// To wait infinitely for the close operations to complete use . + /// + /// + public static void Close(this IConnection connection, TimeSpan timeout) + { + connection.Close(Constants.ReplySuccess, "Goodbye", timeout, false); + } - /// - /// Close this connection and all its channels - /// and wait with a timeout for all the in-progress close operations to complete. - /// - /// - /// The method behaves in the same way as , with the only - /// difference that the connection is closed with the given connection close code and message. - /// - /// The close code (See under "Reply Codes" in the AMQP 0-9-1 specification). - /// - /// - /// A message indicating the reason for closing the connection. - /// - /// - /// Operation timeout. - /// - /// - public static void Close(this IConnection connection, ushort reasonCode, string reasonText, TimeSpan timeout) - { - connection.Close(reasonCode, reasonText, timeout, false); - } + /// + /// Close this connection and all its channels + /// and wait with a timeout for all the in-progress close operations to complete. + /// + /// + /// The method behaves in the same way as , with the only + /// difference that the connection is closed with the given connection close code and message. + /// + /// The close code (See under "Reply Codes" in the AMQP 0-9-1 specification). + /// + /// + /// A message indicating the reason for closing the connection. + /// + /// + /// Operation timeout. + /// + /// + public static void Close(this IConnection connection, ushort reasonCode, string reasonText, TimeSpan timeout) + { + connection.Close(reasonCode, reasonText, timeout, false); + } - /// - /// Abort this connection and all its channels. - /// - /// - /// Note that all active channels, sessions, and models will be closed if this method is called. - /// In comparison to normal method, will not throw - /// during closing connection. - ///This method waits infinitely for the in-progress close operation to complete. - /// - public static void Abort(this IConnection connection) - { - connection.Close(Constants.ReplySuccess, "Connection close forced", InternalConstants.DefaultConnectionAbortTimeout, true); - } + /// + /// Abort this connection and all its channels. + /// + /// + /// Note that all active channels, sessions, and models will be closed if this method is called. + /// In comparison to normal method, will not throw + /// during closing connection. + ///This method waits infinitely for the in-progress close operation to complete. + /// + public static void Abort(this IConnection connection) + { + connection.Close(Constants.ReplySuccess, "Connection close forced", InternalConstants.DefaultConnectionAbortTimeout, true); + } - /// - /// Abort this connection and all its channels. - /// - /// - /// The method behaves in the same way as , with the only - /// difference that the connection is closed with the given connection close code and message. - /// - /// The close code (See under "Reply Codes" in the AMQP 0-9-1 specification) - /// - /// - /// A message indicating the reason for closing the connection - /// - /// - public static void Abort(this IConnection connection, ushort reasonCode, string reasonText) - { - connection.Close(reasonCode, reasonText, InternalConstants.DefaultConnectionAbortTimeout, true); - } + /// + /// Abort this connection and all its channels. + /// + /// + /// The method behaves in the same way as , with the only + /// difference that the connection is closed with the given connection close code and message. + /// + /// The close code (See under "Reply Codes" in the AMQP 0-9-1 specification) + /// + /// + /// A message indicating the reason for closing the connection + /// + /// + public static void Abort(this IConnection connection, ushort reasonCode, string reasonText) + { + connection.Close(reasonCode, reasonText, InternalConstants.DefaultConnectionAbortTimeout, true); + } - /// - /// Abort this connection and all its channels and wait with a - /// timeout for all the in-progress close operations to complete. - /// - /// - /// This method, behaves in a similar way as method with the - /// only difference that it explicitly specifies a timeout given - /// for all the in-progress close operations to complete. - /// If timeout is reached and the close operations haven't finished, then socket is forced to close. - /// - /// To wait infinitely for the close operations to complete use . - /// - /// - public static void Abort(this IConnection connection, TimeSpan timeout) - { - connection.Close(Constants.ReplySuccess, "Connection close forced", timeout, true); - } + /// + /// Abort this connection and all its channels and wait with a + /// timeout for all the in-progress close operations to complete. + /// + /// + /// This method, behaves in a similar way as method with the + /// only difference that it explicitly specifies a timeout given + /// for all the in-progress close operations to complete. + /// If timeout is reached and the close operations haven't finished, then socket is forced to close. + /// + /// To wait infinitely for the close operations to complete use . + /// + /// + public static void Abort(this IConnection connection, TimeSpan timeout) + { + connection.Close(Constants.ReplySuccess, "Connection close forced", timeout, true); + } - /// - /// Abort this connection and all its channels and wait with a - /// timeout for all the in-progress close operations to complete. - /// - /// - /// The method behaves in the same way as , with the only - /// difference that the connection is closed with the given connection close code and message. - /// - /// The close code (See under "Reply Codes" in the AMQP 0-9-1 specification). - /// - /// - /// A message indicating the reason for closing the connection. - /// - /// - public static void Abort(this IConnection connection, ushort reasonCode, string reasonText, TimeSpan timeout) - { - connection.Close(reasonCode, reasonText, timeout, true); + /// + /// Abort this connection and all its channels and wait with a + /// timeout for all the in-progress close operations to complete. + /// + /// + /// The method behaves in the same way as , with the only + /// difference that the connection is closed with the given connection close code and message. + /// + /// The close code (See under "Reply Codes" in the AMQP 0-9-1 specification). + /// + /// + /// A message indicating the reason for closing the connection. + /// + /// + public static void Abort(this IConnection connection, ushort reasonCode, string reasonText, TimeSpan timeout) + { + connection.Close(reasonCode, reasonText, timeout, true); + } } } diff --git a/projects/RabbitMQ.Client/client/api/IConnectionFactory.cs b/projects/RabbitMQ.Client/client/api/IConnectionFactory.cs index 289e467b24..4f8736baa6 100644 --- a/projects/RabbitMQ.Client/client/api/IConnectionFactory.cs +++ b/projects/RabbitMQ.Client/client/api/IConnectionFactory.cs @@ -34,157 +34,158 @@ using RabbitMQ.Client.Exceptions; -namespace RabbitMQ.Client; - -public interface IConnectionFactory +namespace RabbitMQ.Client { - /// - /// Dictionary of client properties to be sent to the server. - /// - IDictionary ClientProperties { get; set; } - - /// - /// Password to use when authenticating to the server. - /// - string Password { get; set; } - - /// - /// Maximum channel number to ask for. - /// - ushort RequestedChannelMax { get; set; } - - /// - /// Frame-max parameter to ask for (in bytes). - /// - uint RequestedFrameMax { get; set; } - - /// - /// Heartbeat setting to request. - /// - TimeSpan RequestedHeartbeat { get; set; } - - /// - /// Username to use when authenticating to the server. - /// - string UserName { get; set; } - - /// - /// Virtual host to access during this connection. - /// - string VirtualHost { get; set; } - - /// - /// Sets or gets the AMQP Uri to be used for connections. - /// - Uri Uri { get; set; } - - /// - /// Default client provided name to be used for connections. - /// - string ClientProvidedName { get; set; } - - /// - /// Given a list of mechanism names supported by the server, select a preferred mechanism, - /// or null if we have none in common. - /// - IAuthMechanismFactory AuthMechanismFactory(IList mechanismNames); - - /// - /// Create a connection to the specified endpoint. - /// - IConnection CreateConnection(); - - /// - /// Create a connection to the specified endpoint. - /// - /// - /// Application-specific connection name, will be displayed in the management UI - /// if RabbitMQ server supports it. This value doesn't have to be unique and cannot - /// be used as a connection identifier, e.g. in HTTP API requests. - /// This value is supposed to be human-readable. - /// - /// Open connection - IConnection CreateConnection(string clientProvidedName); - - /// - /// Connects to the first reachable hostname from the list. - /// - /// List of host names to use - /// Open connection - IConnection CreateConnection(IList hostnames); - - /// - /// Connects to the first reachable hostname from the list. - /// - /// List of host names to use - /// - /// Application-specific connection name, will be displayed in the management UI - /// if RabbitMQ server supports it. This value doesn't have to be unique and cannot - /// be used as a connection identifier, e.g. in HTTP API requests. - /// This value is supposed to be human-readable. - /// - /// Open connection - IConnection CreateConnection(IList hostnames, string clientProvidedName); - - /// - /// Create a connection using a list of endpoints. - /// The selection behaviour can be overridden by configuring the EndpointResolverFactory. - /// - /// - /// List of endpoints to use for the initial - /// connection and recovery. - /// - /// Open connection - /// - /// When no hostname was reachable. - /// - IConnection CreateConnection(IList endpoints); - - /// - /// Create a connection using a list of endpoints. - /// The selection behaviour can be overridden by configuring the EndpointResolverFactory. - /// - /// - /// List of endpoints to use for the initial - /// connection and recovery. - /// - /// - /// Application-specific connection name, will be displayed in the management UI - /// if RabbitMQ server supports it. This value doesn't have to be unique and cannot - /// be used as a connection identifier, e.g. in HTTP API requests. - /// This value is supposed to be human-readable. - /// - /// Open connection - /// - /// When no hostname was reachable. - /// - IConnection CreateConnection(IList endpoints, string clientProvidedName); - - /// - /// Amount of time protocol handshake operations are allowed to take before - /// timing out. - /// - TimeSpan HandshakeContinuationTimeout { get; set; } - - /// - /// Amount of time protocol operations (e.g. queue.declare) are allowed to take before - /// timing out. - /// - TimeSpan ContinuationTimeout { get; set; } - - /// - /// Gets or sets a value indicating whether an asynchronous consumer dispatcher which is compatible with is used. - /// - /// if an asynchronous consumer dispatcher which is compatible with is used; otherwise, . - bool DispatchConsumersAsync { get; set; } - - /// - /// Set to a value greater than one to enable concurrent processing. For a concurrency greater than one - /// will be offloaded to the worker thread pool so it is important to choose the value for the concurrency wisely to avoid thread pool overloading. - /// can handle concurrency much more efficiently due to the non-blocking nature of the consumer. - /// Defaults to 1. - /// - /// For concurrency greater than one this removes the guarantee that consumers handle messages in the order they receive them. - /// In addition to that consumers need to be thread/concurrency safe. - int ConsumerDispatchConcurrency { get; set; } + public interface IConnectionFactory + { + /// + /// Dictionary of client properties to be sent to the server. + /// + IDictionary ClientProperties { get; set; } + + /// + /// Password to use when authenticating to the server. + /// + string Password { get; set; } + + /// + /// Maximum channel number to ask for. + /// + ushort RequestedChannelMax { get; set; } + + /// + /// Frame-max parameter to ask for (in bytes). + /// + uint RequestedFrameMax { get; set; } + + /// + /// Heartbeat setting to request. + /// + TimeSpan RequestedHeartbeat { get; set; } + + /// + /// Username to use when authenticating to the server. + /// + string UserName { get; set; } + + /// + /// Virtual host to access during this connection. + /// + string VirtualHost { get; set; } + + /// + /// Sets or gets the AMQP Uri to be used for connections. + /// + Uri Uri { get; set; } + + /// + /// Default client provided name to be used for connections. + /// + string ClientProvidedName { get; set; } + + /// + /// Given a list of mechanism names supported by the server, select a preferred mechanism, + /// or null if we have none in common. + /// + IAuthMechanismFactory AuthMechanismFactory(IList mechanismNames); + + /// + /// Create a connection to the specified endpoint. + /// + IConnection CreateConnection(); + + /// + /// Create a connection to the specified endpoint. + /// + /// + /// Application-specific connection name, will be displayed in the management UI + /// if RabbitMQ server supports it. This value doesn't have to be unique and cannot + /// be used as a connection identifier, e.g. in HTTP API requests. + /// This value is supposed to be human-readable. + /// + /// Open connection + IConnection CreateConnection(string clientProvidedName); + + /// + /// Connects to the first reachable hostname from the list. + /// + /// List of host names to use + /// Open connection + IConnection CreateConnection(IList hostnames); + + /// + /// Connects to the first reachable hostname from the list. + /// + /// List of host names to use + /// + /// Application-specific connection name, will be displayed in the management UI + /// if RabbitMQ server supports it. This value doesn't have to be unique and cannot + /// be used as a connection identifier, e.g. in HTTP API requests. + /// This value is supposed to be human-readable. + /// + /// Open connection + IConnection CreateConnection(IList hostnames, string clientProvidedName); + + /// + /// Create a connection using a list of endpoints. + /// The selection behaviour can be overridden by configuring the EndpointResolverFactory. + /// + /// + /// List of endpoints to use for the initial + /// connection and recovery. + /// + /// Open connection + /// + /// When no hostname was reachable. + /// + IConnection CreateConnection(IList endpoints); + + /// + /// Create a connection using a list of endpoints. + /// The selection behaviour can be overridden by configuring the EndpointResolverFactory. + /// + /// + /// List of endpoints to use for the initial + /// connection and recovery. + /// + /// + /// Application-specific connection name, will be displayed in the management UI + /// if RabbitMQ server supports it. This value doesn't have to be unique and cannot + /// be used as a connection identifier, e.g. in HTTP API requests. + /// This value is supposed to be human-readable. + /// + /// Open connection + /// + /// When no hostname was reachable. + /// + IConnection CreateConnection(IList endpoints, string clientProvidedName); + + /// + /// Amount of time protocol handshake operations are allowed to take before + /// timing out. + /// + TimeSpan HandshakeContinuationTimeout { get; set; } + + /// + /// Amount of time protocol operations (e.g. queue.declare) are allowed to take before + /// timing out. + /// + TimeSpan ContinuationTimeout { get; set; } + + /// + /// Gets or sets a value indicating whether an asynchronous consumer dispatcher which is compatible with is used. + /// + /// if an asynchronous consumer dispatcher which is compatible with is used; otherwise, . + bool DispatchConsumersAsync { get; set; } + + /// + /// Set to a value greater than one to enable concurrent processing. For a concurrency greater than one + /// will be offloaded to the worker thread pool so it is important to choose the value for the concurrency wisely to avoid thread pool overloading. + /// can handle concurrency much more efficiently due to the non-blocking nature of the consumer. + /// Defaults to 1. + /// + /// For concurrency greater than one this removes the guarantee that consumers handle messages in the order they receive them. + /// In addition to that consumers need to be thread/concurrency safe. + int ConsumerDispatchConcurrency { get; set; } + } } diff --git a/projects/RabbitMQ.Client/client/api/IEndpointResolver.cs b/projects/RabbitMQ.Client/client/api/IEndpointResolver.cs index a0997e196e..6cfbb70cbd 100644 --- a/projects/RabbitMQ.Client/client/api/IEndpointResolver.cs +++ b/projects/RabbitMQ.Client/client/api/IEndpointResolver.cs @@ -31,12 +31,13 @@ using System.Collections.Generic; -namespace RabbitMQ.Client; - -public interface IEndpointResolver +namespace RabbitMQ.Client { - /// - /// Return all AmqpTcpEndpoints in the order they should be tried. - /// - IEnumerable All(); + public interface IEndpointResolver + { + /// + /// Return all AmqpTcpEndpoints in the order they should be tried. + /// + IEnumerable All(); + } } diff --git a/projects/RabbitMQ.Client/client/api/IEndpointResolverExtensions.cs b/projects/RabbitMQ.Client/client/api/IEndpointResolverExtensions.cs index a937ab0dd5..29035d5b49 100644 --- a/projects/RabbitMQ.Client/client/api/IEndpointResolverExtensions.cs +++ b/projects/RabbitMQ.Client/client/api/IEndpointResolverExtensions.cs @@ -32,36 +32,37 @@ using System; using System.Collections.Generic; -namespace RabbitMQ.Client; - -public static class EndpointResolverExtensions +namespace RabbitMQ.Client { - public static T SelectOne(this IEndpointResolver resolver, Func selector) + public static class EndpointResolverExtensions { - var t = default(T); - List exceptions = null; - foreach (AmqpTcpEndpoint ep in resolver.All()) + public static T SelectOne(this IEndpointResolver resolver, Func selector) { - try + var t = default(T); + List exceptions = null; + foreach (AmqpTcpEndpoint ep in resolver.All()) { - t = selector(ep); - if (t.Equals(default(T)) == false) + try + { + t = selector(ep); + if (t.Equals(default(T)) == false) + { + return t; + } + } + catch (Exception e) { - return t; + exceptions ??= new List(1); + exceptions.Add(e); } } - catch (Exception e) + + if (Object.Equals(t, default(T)) && exceptions?.Count > 0) { - exceptions ??= new List(1); - exceptions.Add(e); + throw new AggregateException(exceptions); } - } - if (Object.Equals(t, default(T)) && exceptions?.Count > 0) - { - throw new AggregateException(exceptions); + return t; } - - return t; } } diff --git a/projects/RabbitMQ.Client/client/api/IModel.cs b/projects/RabbitMQ.Client/client/api/IModel.cs index 143ec5200d..085dc686e6 100644 --- a/projects/RabbitMQ.Client/client/api/IModel.cs +++ b/projects/RabbitMQ.Client/client/api/IModel.cs @@ -35,412 +35,413 @@ using System.Threading.Tasks; using RabbitMQ.Client.Events; -namespace RabbitMQ.Client; - -/// -/// Common AMQP model, spanning the union of the -/// functionality offered by versions 0-8, 0-8qpid, 0-9 and 0-9-1 of AMQP. -/// -/// -/// Extends the interface, so that the "using" -/// statement can be used to scope the lifetime of a channel when appropriate. -/// -public interface IModel : IDisposable +namespace RabbitMQ.Client { /// - /// Channel number, unique per connections. - /// - int ChannelNumber { get; } - - /// - /// Returns null if the session is still in a state where it can be used, - /// or the cause of its closure otherwise. - /// - ShutdownEventArgs CloseReason { get; } - - /// Signalled when an unexpected message is delivered - /// - /// Under certain circumstances it is possible for a channel to receive a - /// message delivery which does not match any consumer which is currently - /// set up via basicConsume(). This will occur after the following sequence - /// of events: - /// - /// ctag = basicConsume(queue, consumer); // i.e. with explicit acks - /// // some deliveries take place but are not acked - /// basicCancel(ctag); - /// basicRecover(false); - /// - /// Since requeue is specified to be false in the basicRecover, the spec - /// states that the message must be redelivered to "the original recipient" - /// - i.e. the same channel / consumer-tag. But the consumer is no longer - /// active. - /// - /// In these circumstances, you can register a default consumer to handle - /// such deliveries. If no default consumer is registered an - /// InvalidOperationException will be thrown when such a delivery arrives. - /// - /// Most people will not need to use this. - IBasicConsumer DefaultConsumer { get; set; } - - /// - /// Returns true if the model is no longer in a state where it can be used. - /// - bool IsClosed { get; } - - /// - /// Returns true if the model is still in a state where it can be used. - /// Identical to checking if equals null. - bool IsOpen { get; } - - /// - /// When in confirm mode, return the sequence number of the next message to be published. - /// - ulong NextPublishSeqNo { get; } - - /// - /// Signalled when a Basic.Ack command arrives from the broker. - /// - event EventHandler BasicAcks; - - /// - /// Signalled when a Basic.Nack command arrives from the broker. - /// - event EventHandler BasicNacks; - - /// - /// All messages received before this fires that haven't been ack'ed will be redelivered. - /// All messages received afterwards won't be. - /// - /// - /// Handlers for this event are invoked by the connection thread. - /// It is sometimes useful to allow that thread to know that a recover-ok - /// has been received, rather than the thread that invoked . - /// - event EventHandler BasicRecoverOk; - - /// - /// Signalled when a Basic.Return command arrives from the broker. - /// - event EventHandler BasicReturn; - - /// - /// Signalled when an exception occurs in a callback invoked by the model. - /// - /// Examples of cases where this event will be signalled - /// include exceptions thrown in methods, or - /// exceptions thrown in delegates etc. - /// - event EventHandler CallbackException; - - event EventHandler FlowControl; - - /// - /// Notifies the destruction of the model. + /// Common AMQP model, spanning the union of the + /// functionality offered by versions 0-8, 0-8qpid, 0-9 and 0-9-1 of AMQP. /// /// - /// If the model is already destroyed at the time an event - /// handler is added to this event, the event handler will be fired immediately. + /// Extends the interface, so that the "using" + /// statement can be used to scope the lifetime of a channel when appropriate. /// - event EventHandler ModelShutdown; - - /// - /// Acknowledge one or more delivered message(s). - /// - void BasicAck(ulong deliveryTag, bool multiple); - - /// - /// Delete a Basic content-class consumer. - /// - void BasicCancel(string consumerTag); - - /// - /// Same as BasicCancel but sets nowait to true and returns void (as there - /// will be no response from the server). - /// - void BasicCancelNoWait(string consumerTag); - - /// Start a Basic content-class consumer. - string BasicConsume( - string queue, - bool autoAck, - string consumerTag, - bool noLocal, - bool exclusive, - IDictionary arguments, - IBasicConsumer consumer); - - /// - /// Retrieve an individual message, if - /// one is available; returns null if the server answers that - /// no messages are currently available. See also . - /// - BasicGetResult BasicGet(string queue, bool autoAck); - - /// Reject one or more delivered message(s). - void BasicNack(ulong deliveryTag, bool multiple, bool requeue); + public interface IModel : IDisposable + { + /// + /// Channel number, unique per connections. + /// + int ChannelNumber { get; } + + /// + /// Returns null if the session is still in a state where it can be used, + /// or the cause of its closure otherwise. + /// + ShutdownEventArgs CloseReason { get; } + + /// Signalled when an unexpected message is delivered + /// + /// Under certain circumstances it is possible for a channel to receive a + /// message delivery which does not match any consumer which is currently + /// set up via basicConsume(). This will occur after the following sequence + /// of events: + /// + /// ctag = basicConsume(queue, consumer); // i.e. with explicit acks + /// // some deliveries take place but are not acked + /// basicCancel(ctag); + /// basicRecover(false); + /// + /// Since requeue is specified to be false in the basicRecover, the spec + /// states that the message must be redelivered to "the original recipient" + /// - i.e. the same channel / consumer-tag. But the consumer is no longer + /// active. + /// + /// In these circumstances, you can register a default consumer to handle + /// such deliveries. If no default consumer is registered an + /// InvalidOperationException will be thrown when such a delivery arrives. + /// + /// Most people will not need to use this. + IBasicConsumer DefaultConsumer { get; set; } + + /// + /// Returns true if the model is no longer in a state where it can be used. + /// + bool IsClosed { get; } + + /// + /// Returns true if the model is still in a state where it can be used. + /// Identical to checking if equals null. + bool IsOpen { get; } + + /// + /// When in confirm mode, return the sequence number of the next message to be published. + /// + ulong NextPublishSeqNo { get; } + + /// + /// Signalled when a Basic.Ack command arrives from the broker. + /// + event EventHandler BasicAcks; + + /// + /// Signalled when a Basic.Nack command arrives from the broker. + /// + event EventHandler BasicNacks; + + /// + /// All messages received before this fires that haven't been ack'ed will be redelivered. + /// All messages received afterwards won't be. + /// + /// + /// Handlers for this event are invoked by the connection thread. + /// It is sometimes useful to allow that thread to know that a recover-ok + /// has been received, rather than the thread that invoked . + /// + event EventHandler BasicRecoverOk; + + /// + /// Signalled when a Basic.Return command arrives from the broker. + /// + event EventHandler BasicReturn; + + /// + /// Signalled when an exception occurs in a callback invoked by the model. + /// + /// Examples of cases where this event will be signalled + /// include exceptions thrown in methods, or + /// exceptions thrown in delegates etc. + /// + event EventHandler CallbackException; + + event EventHandler FlowControl; + + /// + /// Notifies the destruction of the model. + /// + /// + /// If the model is already destroyed at the time an event + /// handler is added to this event, the event handler will be fired immediately. + /// + event EventHandler ModelShutdown; + + /// + /// Acknowledge one or more delivered message(s). + /// + void BasicAck(ulong deliveryTag, bool multiple); + + /// + /// Delete a Basic content-class consumer. + /// + void BasicCancel(string consumerTag); + + /// + /// Same as BasicCancel but sets nowait to true and returns void (as there + /// will be no response from the server). + /// + void BasicCancelNoWait(string consumerTag); + + /// Start a Basic content-class consumer. + string BasicConsume( + string queue, + bool autoAck, + string consumerTag, + bool noLocal, + bool exclusive, + IDictionary arguments, + IBasicConsumer consumer); + + /// + /// Retrieve an individual message, if + /// one is available; returns null if the server answers that + /// no messages are currently available. See also . + /// + BasicGetResult BasicGet(string queue, bool autoAck); + + /// Reject one or more delivered message(s). + void BasicNack(ulong deliveryTag, bool multiple, bool requeue); #nullable enable - /// - /// Publishes a message. - /// - /// - /// - /// Routing key must be shorter than 255 bytes. - /// - /// - void BasicPublish(string exchange, string routingKey, ref TProperties basicProperties, ReadOnlyMemory body = default, bool mandatory = false) - where TProperties : IReadOnlyBasicProperties, IAmqpHeader; - /// - /// Publishes a message. - /// - /// - /// - /// Routing key must be shorter than 255 bytes. - /// - /// - void BasicPublish(CachedString exchange, CachedString routingKey, ref TProperties basicProperties, ReadOnlyMemory body = default, bool mandatory = false) - where TProperties : IReadOnlyBasicProperties, IAmqpHeader; + /// + /// Publishes a message. + /// + /// + /// + /// Routing key must be shorter than 255 bytes. + /// + /// + void BasicPublish(string exchange, string routingKey, ref TProperties basicProperties, ReadOnlyMemory body = default, bool mandatory = false) + where TProperties : IReadOnlyBasicProperties, IAmqpHeader; + /// + /// Publishes a message. + /// + /// + /// + /// Routing key must be shorter than 255 bytes. + /// + /// + void BasicPublish(CachedString exchange, CachedString routingKey, ref TProperties basicProperties, ReadOnlyMemory body = default, bool mandatory = false) + where TProperties : IReadOnlyBasicProperties, IAmqpHeader; #nullable disable - /// - /// Configures QoS parameters of the Basic content-class. - /// - void BasicQos(uint prefetchSize, ushort prefetchCount, bool global); - - /// - /// Indicates that a consumer has recovered. - /// Deprecated. Should not be used. - /// - void BasicRecover(bool requeue); - - /// - /// Indicates that a consumer has recovered. - /// Deprecated. Should not be used. - /// - void BasicRecoverAsync(bool requeue); - - /// Reject a delivered message. - void BasicReject(ulong deliveryTag, bool requeue); - - /// Close this session. - /// The reply code to send for closing (See under "Reply Codes" in the AMQP specification). - /// The reply text to send for closing. - /// Whether or not the close is an abort (ignoring certain exceptions). - void Close(ushort replyCode, string replyText, bool abort); - - /// - /// Enable publisher acknowledgements. - /// - void ConfirmSelect(); - - /// - /// Bind an exchange to an exchange. - /// - /// - /// - /// Routing key must be shorter than 255 bytes. - /// - /// - void ExchangeBind(string destination, string source, string routingKey, IDictionary arguments); - - /// - /// Like ExchangeBind but sets nowait to true. - /// - /// - /// - /// Routing key must be shorter than 255 bytes. - /// - /// - void ExchangeBindNoWait(string destination, string source, string routingKey, IDictionary arguments); - - /// Declare an exchange. - /// - /// The exchange is declared non-passive and non-internal. - /// The "nowait" option is not exercised. - /// - void ExchangeDeclare(string exchange, string type, bool durable, bool autoDelete, IDictionary arguments); - - /// - /// Same as ExchangeDeclare but sets nowait to true and returns void (as there - /// will be no response from the server). - /// - void ExchangeDeclareNoWait(string exchange, string type, bool durable, bool autoDelete, IDictionary arguments); - - /// - /// Do a passive exchange declaration. - /// - /// - /// This method performs a "passive declare" on an exchange, - /// which checks whether an exchange exists. - /// It will do nothing if the exchange already exists and result - /// in a channel-level protocol exception (channel closure) if not. - /// - void ExchangeDeclarePassive(string exchange); - - /// - /// Delete an exchange. - /// - void ExchangeDelete(string exchange, bool ifUnused); - - /// - /// Like ExchangeDelete but sets nowait to true. - /// - void ExchangeDeleteNoWait(string exchange, bool ifUnused); - - /// - /// Unbind an exchange from an exchange. - /// - /// - /// Routing key must be shorter than 255 bytes. - /// - void ExchangeUnbind(string destination, string source, string routingKey, IDictionary arguments); - - /// - /// Like ExchangeUnbind but sets nowait to true. - /// - /// - /// - /// Routing key must be shorter than 255 bytes. - /// - /// - void ExchangeUnbindNoWait(string destination, string source, string routingKey, IDictionary arguments); - - /// - /// Bind a queue to an exchange. - /// - /// - /// - /// Routing key must be shorter than 255 bytes. - /// - /// - void QueueBind(string queue, string exchange, string routingKey, IDictionary arguments); - - /// Same as QueueBind but sets nowait parameter to true. - /// - /// - /// Routing key must be shorter than 255 bytes. - /// - /// - void QueueBindNoWait(string queue, string exchange, string routingKey, IDictionary arguments); - - /// - /// Declares a queue. See the Queues guide to learn more. - /// - /// The name of the queue. Pass an empty string to make the server generate a name. - /// Should this queue will survive a broker restart? - /// Should this queue use be limited to its declaring connection? Such a queue will be deleted when its declaring connection closes. - /// Should this queue be auto-deleted when its last consumer (if any) unsubscribes? - /// Optional; additional queue arguments, e.g. "x-queue-type" - QueueDeclareOk QueueDeclare(string queue, bool durable, bool exclusive, bool autoDelete, IDictionary arguments); - - /// - /// Declares a queue. See the Queues guide to learn more. - /// - /// The name of the queue. Pass an empty string to make the server generate a name. - /// Should this queue will survive a broker restart? - /// Should this queue use be limited to its declaring connection? Such a queue will be deleted when its declaring connection closes. - /// Should this queue be auto-deleted when its last consumer (if any) unsubscribes? - /// Optional; additional queue arguments, e.g. "x-queue-type" - void QueueDeclareNoWait(string queue, bool durable, bool exclusive, bool autoDelete, IDictionary arguments); - - /// Declare a queue passively. - /// - ///The queue is declared passive, non-durable, - ///non-exclusive, and non-autodelete, with no arguments. - ///The queue is declared passively; i.e. only check if it exists. - /// - QueueDeclareOk QueueDeclarePassive(string queue); - - /// - /// Returns the number of messages in a queue ready to be delivered - /// to consumers. This method assumes the queue exists. If it doesn't, - /// an exception will be closed with an exception. - /// - /// The name of the queue - uint MessageCount(string queue); - - /// - /// Returns the number of consumers on a queue. - /// This method assumes the queue exists. If it doesn't, - /// an exception will be closed with an exception. - /// - /// The name of the queue - uint ConsumerCount(string queue); - - /// - /// Delete a queue. - /// - /// - ///Returns the number of messages purged during queue deletion. - /// - uint QueueDelete(string queue, bool ifUnused, bool ifEmpty); - - /// - ///Same as QueueDelete but sets nowait parameter to true - ///and returns void (as there will be no response from the server) - /// - void QueueDeleteNoWait(string queue, bool ifUnused, bool ifEmpty); - - /// - /// Purge a queue of messages. - /// - /// - /// Returns the number of messages purged. - /// - uint QueuePurge(string queue); - - /// - /// Unbind a queue from an exchange. - /// - /// - /// - /// Routing key must be shorter than 255 bytes. - /// - /// - void QueueUnbind(string queue, string exchange, string routingKey, IDictionary arguments); - - /// - /// Commit this session's active TX transaction. - /// - void TxCommit(); - - /// - /// Roll back this session's active TX transaction. - /// - void TxRollback(); - - /// - /// Enable TX mode for this session. - /// - void TxSelect(); - - /// - /// Wait until all published messages have been confirmed. - /// - /// True if no nacks were received within the timeout, otherwise false. - /// The cancellation token. - /// - /// Waits until all messages published since the last call have - /// been either ack'd or nack'd by the broker. Returns whether - /// all the messages were ack'd (and none were nack'd). Note, - /// throws an exception when called on a non-Confirm channel. - /// - Task WaitForConfirmsAsync(CancellationToken token = default); - - /// - /// Wait until all published messages have been confirmed. - /// - /// The cancellation token. - /// - /// Waits until all messages published since the last call have - /// been ack'd by the broker. If a nack is received or the timeout - /// elapses, throws an IOException exception immediately. - /// - Task WaitForConfirmsOrDieAsync(CancellationToken token = default); - - /// - /// Amount of time protocol operations (e.g. queue.declare) are allowed to take before - /// timing out. - /// - TimeSpan ContinuationTimeout { get; set; } + /// + /// Configures QoS parameters of the Basic content-class. + /// + void BasicQos(uint prefetchSize, ushort prefetchCount, bool global); + + /// + /// Indicates that a consumer has recovered. + /// Deprecated. Should not be used. + /// + void BasicRecover(bool requeue); + + /// + /// Indicates that a consumer has recovered. + /// Deprecated. Should not be used. + /// + void BasicRecoverAsync(bool requeue); + + /// Reject a delivered message. + void BasicReject(ulong deliveryTag, bool requeue); + + /// Close this session. + /// The reply code to send for closing (See under "Reply Codes" in the AMQP specification). + /// The reply text to send for closing. + /// Whether or not the close is an abort (ignoring certain exceptions). + void Close(ushort replyCode, string replyText, bool abort); + + /// + /// Enable publisher acknowledgements. + /// + void ConfirmSelect(); + + /// + /// Bind an exchange to an exchange. + /// + /// + /// + /// Routing key must be shorter than 255 bytes. + /// + /// + void ExchangeBind(string destination, string source, string routingKey, IDictionary arguments); + + /// + /// Like ExchangeBind but sets nowait to true. + /// + /// + /// + /// Routing key must be shorter than 255 bytes. + /// + /// + void ExchangeBindNoWait(string destination, string source, string routingKey, IDictionary arguments); + + /// Declare an exchange. + /// + /// The exchange is declared non-passive and non-internal. + /// The "nowait" option is not exercised. + /// + void ExchangeDeclare(string exchange, string type, bool durable, bool autoDelete, IDictionary arguments); + + /// + /// Same as ExchangeDeclare but sets nowait to true and returns void (as there + /// will be no response from the server). + /// + void ExchangeDeclareNoWait(string exchange, string type, bool durable, bool autoDelete, IDictionary arguments); + + /// + /// Do a passive exchange declaration. + /// + /// + /// This method performs a "passive declare" on an exchange, + /// which checks whether an exchange exists. + /// It will do nothing if the exchange already exists and result + /// in a channel-level protocol exception (channel closure) if not. + /// + void ExchangeDeclarePassive(string exchange); + + /// + /// Delete an exchange. + /// + void ExchangeDelete(string exchange, bool ifUnused); + + /// + /// Like ExchangeDelete but sets nowait to true. + /// + void ExchangeDeleteNoWait(string exchange, bool ifUnused); + + /// + /// Unbind an exchange from an exchange. + /// + /// + /// Routing key must be shorter than 255 bytes. + /// + void ExchangeUnbind(string destination, string source, string routingKey, IDictionary arguments); + + /// + /// Like ExchangeUnbind but sets nowait to true. + /// + /// + /// + /// Routing key must be shorter than 255 bytes. + /// + /// + void ExchangeUnbindNoWait(string destination, string source, string routingKey, IDictionary arguments); + + /// + /// Bind a queue to an exchange. + /// + /// + /// + /// Routing key must be shorter than 255 bytes. + /// + /// + void QueueBind(string queue, string exchange, string routingKey, IDictionary arguments); + + /// Same as QueueBind but sets nowait parameter to true. + /// + /// + /// Routing key must be shorter than 255 bytes. + /// + /// + void QueueBindNoWait(string queue, string exchange, string routingKey, IDictionary arguments); + + /// + /// Declares a queue. See the Queues guide to learn more. + /// + /// The name of the queue. Pass an empty string to make the server generate a name. + /// Should this queue will survive a broker restart? + /// Should this queue use be limited to its declaring connection? Such a queue will be deleted when its declaring connection closes. + /// Should this queue be auto-deleted when its last consumer (if any) unsubscribes? + /// Optional; additional queue arguments, e.g. "x-queue-type" + QueueDeclareOk QueueDeclare(string queue, bool durable, bool exclusive, bool autoDelete, IDictionary arguments); + + /// + /// Declares a queue. See the Queues guide to learn more. + /// + /// The name of the queue. Pass an empty string to make the server generate a name. + /// Should this queue will survive a broker restart? + /// Should this queue use be limited to its declaring connection? Such a queue will be deleted when its declaring connection closes. + /// Should this queue be auto-deleted when its last consumer (if any) unsubscribes? + /// Optional; additional queue arguments, e.g. "x-queue-type" + void QueueDeclareNoWait(string queue, bool durable, bool exclusive, bool autoDelete, IDictionary arguments); + + /// Declare a queue passively. + /// + ///The queue is declared passive, non-durable, + ///non-exclusive, and non-autodelete, with no arguments. + ///The queue is declared passively; i.e. only check if it exists. + /// + QueueDeclareOk QueueDeclarePassive(string queue); + + /// + /// Returns the number of messages in a queue ready to be delivered + /// to consumers. This method assumes the queue exists. If it doesn't, + /// an exception will be closed with an exception. + /// + /// The name of the queue + uint MessageCount(string queue); + + /// + /// Returns the number of consumers on a queue. + /// This method assumes the queue exists. If it doesn't, + /// an exception will be closed with an exception. + /// + /// The name of the queue + uint ConsumerCount(string queue); + + /// + /// Delete a queue. + /// + /// + ///Returns the number of messages purged during queue deletion. + /// + uint QueueDelete(string queue, bool ifUnused, bool ifEmpty); + + /// + ///Same as QueueDelete but sets nowait parameter to true + ///and returns void (as there will be no response from the server) + /// + void QueueDeleteNoWait(string queue, bool ifUnused, bool ifEmpty); + + /// + /// Purge a queue of messages. + /// + /// + /// Returns the number of messages purged. + /// + uint QueuePurge(string queue); + + /// + /// Unbind a queue from an exchange. + /// + /// + /// + /// Routing key must be shorter than 255 bytes. + /// + /// + void QueueUnbind(string queue, string exchange, string routingKey, IDictionary arguments); + + /// + /// Commit this session's active TX transaction. + /// + void TxCommit(); + + /// + /// Roll back this session's active TX transaction. + /// + void TxRollback(); + + /// + /// Enable TX mode for this session. + /// + void TxSelect(); + + /// + /// Wait until all published messages have been confirmed. + /// + /// True if no nacks were received within the timeout, otherwise false. + /// The cancellation token. + /// + /// Waits until all messages published since the last call have + /// been either ack'd or nack'd by the broker. Returns whether + /// all the messages were ack'd (and none were nack'd). Note, + /// throws an exception when called on a non-Confirm channel. + /// + Task WaitForConfirmsAsync(CancellationToken token = default); + + /// + /// Wait until all published messages have been confirmed. + /// + /// The cancellation token. + /// + /// Waits until all messages published since the last call have + /// been ack'd by the broker. If a nack is received or the timeout + /// elapses, throws an IOException exception immediately. + /// + Task WaitForConfirmsOrDieAsync(CancellationToken token = default); + + /// + /// Amount of time protocol operations (e.g. queue.declare) are allowed to take before + /// timing out. + /// + TimeSpan ContinuationTimeout { get; set; } + } } diff --git a/projects/RabbitMQ.Client/client/api/IModelExtensions.cs b/projects/RabbitMQ.Client/client/api/IModelExtensions.cs index e711b9bdc0..d7df884227 100644 --- a/projects/RabbitMQ.Client/client/api/IModelExtensions.cs +++ b/projects/RabbitMQ.Client/client/api/IModelExtensions.cs @@ -33,230 +33,231 @@ using System.Collections.Generic; using RabbitMQ.Client.client.impl; -namespace RabbitMQ.Client; - -public static class IModelExtensions +namespace RabbitMQ.Client { - /// Start a Basic content-class consumer. - public static string BasicConsume(this IModel model, - IBasicConsumer consumer, - string queue, - bool autoAck = false, - string consumerTag = "", - bool noLocal = false, - bool exclusive = false, - IDictionary arguments = null) + public static class IModelExtensions { - return model.BasicConsume(queue, autoAck, consumerTag, noLocal, exclusive, arguments, consumer); - } + /// Start a Basic content-class consumer. + public static string BasicConsume(this IModel model, + IBasicConsumer consumer, + string queue, + bool autoAck = false, + string consumerTag = "", + bool noLocal = false, + bool exclusive = false, + IDictionary arguments = null) + { + return model.BasicConsume(queue, autoAck, consumerTag, noLocal, exclusive, arguments, consumer); + } - /// Start a Basic content-class consumer. - public static string BasicConsume(this IModel model, string queue, bool autoAck, IBasicConsumer consumer) - { - return model.BasicConsume(queue, autoAck, "", false, false, null, consumer); - } + /// Start a Basic content-class consumer. + public static string BasicConsume(this IModel model, string queue, bool autoAck, IBasicConsumer consumer) + { + return model.BasicConsume(queue, autoAck, "", false, false, null, consumer); + } - /// Start a Basic content-class consumer. - public static string BasicConsume(this IModel model, string queue, - bool autoAck, - string consumerTag, - IBasicConsumer consumer) - { - return model.BasicConsume(queue, autoAck, consumerTag, false, false, null, consumer); - } + /// Start a Basic content-class consumer. + public static string BasicConsume(this IModel model, string queue, + bool autoAck, + string consumerTag, + IBasicConsumer consumer) + { + return model.BasicConsume(queue, autoAck, consumerTag, false, false, null, consumer); + } - /// Start a Basic content-class consumer. - public static string BasicConsume(this IModel model, string queue, - bool autoAck, - string consumerTag, - IDictionary arguments, - IBasicConsumer consumer) - { - return model.BasicConsume(queue, autoAck, consumerTag, false, false, arguments, consumer); - } + /// Start a Basic content-class consumer. + public static string BasicConsume(this IModel model, string queue, + bool autoAck, + string consumerTag, + IDictionary arguments, + IBasicConsumer consumer) + { + return model.BasicConsume(queue, autoAck, consumerTag, false, false, arguments, consumer); + } #nullable enable - /// - /// (Extension method) Convenience overload of BasicPublish. - /// - /// - /// The publication occurs with mandatory=false and immediate=false. - /// - public static void BasicPublish(this IModel model, PublicationAddress addr, ref T basicProperties, ReadOnlyMemory body) - where T : IReadOnlyBasicProperties, IAmqpHeader - { - model.BasicPublish(addr.ExchangeName, addr.RoutingKey, ref basicProperties, body); - } + /// + /// (Extension method) Convenience overload of BasicPublish. + /// + /// + /// The publication occurs with mandatory=false and immediate=false. + /// + public static void BasicPublish(this IModel model, PublicationAddress addr, ref T basicProperties, ReadOnlyMemory body) + where T : IReadOnlyBasicProperties, IAmqpHeader + { + model.BasicPublish(addr.ExchangeName, addr.RoutingKey, ref basicProperties, body); + } - public static void BasicPublish(this IModel model, string exchange, string routingKey, ReadOnlyMemory body = default, bool mandatory = false) - => model.BasicPublish(exchange, routingKey, ref EmptyBasicProperty.Empty, body, mandatory); + public static void BasicPublish(this IModel model, string exchange, string routingKey, ReadOnlyMemory body = default, bool mandatory = false) + => model.BasicPublish(exchange, routingKey, ref EmptyBasicProperty.Empty, body, mandatory); - public static void BasicPublish(this IModel model, CachedString exchange, CachedString routingKey, ReadOnlyMemory body = default, bool mandatory = false) - => model.BasicPublish(exchange, routingKey, ref EmptyBasicProperty.Empty, body, mandatory); + public static void BasicPublish(this IModel model, CachedString exchange, CachedString routingKey, ReadOnlyMemory body = default, bool mandatory = false) + => model.BasicPublish(exchange, routingKey, ref EmptyBasicProperty.Empty, body, mandatory); #nullable disable - /// - /// (Spec method) Declare a queue. - /// - public static QueueDeclareOk QueueDeclare(this IModel model, string queue = "", bool durable = false, bool exclusive = true, - bool autoDelete = true, IDictionary arguments = null) - { - return model.QueueDeclare(queue, durable, exclusive, autoDelete, arguments); - } + /// + /// (Spec method) Declare a queue. + /// + public static QueueDeclareOk QueueDeclare(this IModel model, string queue = "", bool durable = false, bool exclusive = true, + bool autoDelete = true, IDictionary arguments = null) + { + return model.QueueDeclare(queue, durable, exclusive, autoDelete, arguments); + } - /// - /// (Extension method) Bind an exchange to an exchange. - /// - public static void ExchangeBind(this IModel model, string destination, string source, string routingKey, IDictionary arguments = null) - { - model.ExchangeBind(destination, source, routingKey, arguments); - } + /// + /// (Extension method) Bind an exchange to an exchange. + /// + public static void ExchangeBind(this IModel model, string destination, string source, string routingKey, IDictionary arguments = null) + { + model.ExchangeBind(destination, source, routingKey, arguments); + } - /// - /// (Extension method) Like exchange bind but sets nowait to true. - /// - public static void ExchangeBindNoWait(this IModel model, string destination, string source, string routingKey, IDictionary arguments = null) - { - model.ExchangeBindNoWait(destination, source, routingKey, arguments); - } + /// + /// (Extension method) Like exchange bind but sets nowait to true. + /// + public static void ExchangeBindNoWait(this IModel model, string destination, string source, string routingKey, IDictionary arguments = null) + { + model.ExchangeBindNoWait(destination, source, routingKey, arguments); + } - /// - /// (Spec method) Declare an exchange. - /// - public static void ExchangeDeclare(this IModel model, string exchange, string type, bool durable = false, bool autoDelete = false, - IDictionary arguments = null) - { - model.ExchangeDeclare(exchange, type, durable, autoDelete, arguments); - } + /// + /// (Spec method) Declare an exchange. + /// + public static void ExchangeDeclare(this IModel model, string exchange, string type, bool durable = false, bool autoDelete = false, + IDictionary arguments = null) + { + model.ExchangeDeclare(exchange, type, durable, autoDelete, arguments); + } - /// - /// (Extension method) Like ExchangeDeclare but sets nowait to true. - /// - public static void ExchangeDeclareNoWait(this IModel model, string exchange, string type, bool durable = false, bool autoDelete = false, - IDictionary arguments = null) - { - model.ExchangeDeclareNoWait(exchange, type, durable, autoDelete, arguments); - } + /// + /// (Extension method) Like ExchangeDeclare but sets nowait to true. + /// + public static void ExchangeDeclareNoWait(this IModel model, string exchange, string type, bool durable = false, bool autoDelete = false, + IDictionary arguments = null) + { + model.ExchangeDeclareNoWait(exchange, type, durable, autoDelete, arguments); + } - /// - /// (Spec method) Unbinds an exchange. - /// - public static void ExchangeUnbind(this IModel model, string destination, - string source, - string routingKey, - IDictionary arguments = null) - { - model.ExchangeUnbind(destination, source, routingKey, arguments); - } + /// + /// (Spec method) Unbinds an exchange. + /// + public static void ExchangeUnbind(this IModel model, string destination, + string source, + string routingKey, + IDictionary arguments = null) + { + model.ExchangeUnbind(destination, source, routingKey, arguments); + } - /// - /// (Spec method) Deletes an exchange. - /// - public static void ExchangeDelete(this IModel model, string exchange, bool ifUnused = false) - { - model.ExchangeDelete(exchange, ifUnused); - } + /// + /// (Spec method) Deletes an exchange. + /// + public static void ExchangeDelete(this IModel model, string exchange, bool ifUnused = false) + { + model.ExchangeDelete(exchange, ifUnused); + } - /// - /// (Extension method) Like ExchangeDelete but sets nowait to true. - /// - public static void ExchangeDeleteNoWait(this IModel model, string exchange, bool ifUnused = false) - { - model.ExchangeDeleteNoWait(exchange, ifUnused); - } + /// + /// (Extension method) Like ExchangeDelete but sets nowait to true. + /// + public static void ExchangeDeleteNoWait(this IModel model, string exchange, bool ifUnused = false) + { + model.ExchangeDeleteNoWait(exchange, ifUnused); + } - /// - /// (Spec method) Binds a queue. - /// - public static void QueueBind(this IModel model, string queue, string exchange, string routingKey, IDictionary arguments = null) - { - model.QueueBind(queue, exchange, routingKey, arguments); - } + /// + /// (Spec method) Binds a queue. + /// + public static void QueueBind(this IModel model, string queue, string exchange, string routingKey, IDictionary arguments = null) + { + model.QueueBind(queue, exchange, routingKey, arguments); + } - /// - /// (Spec method) Deletes a queue. - /// - public static uint QueueDelete(this IModel model, string queue, bool ifUnused = false, bool ifEmpty = false) - { - return model.QueueDelete(queue, ifUnused, ifEmpty); - } + /// + /// (Spec method) Deletes a queue. + /// + public static uint QueueDelete(this IModel model, string queue, bool ifUnused = false, bool ifEmpty = false) + { + return model.QueueDelete(queue, ifUnused, ifEmpty); + } - /// - /// (Extension method) Like QueueDelete but sets nowait to true. - /// - public static void QueueDeleteNoWait(this IModel model, string queue, bool ifUnused = false, bool ifEmpty = false) - { - model.QueueDeleteNoWait(queue, ifUnused, ifEmpty); - } + /// + /// (Extension method) Like QueueDelete but sets nowait to true. + /// + public static void QueueDeleteNoWait(this IModel model, string queue, bool ifUnused = false, bool ifEmpty = false) + { + model.QueueDeleteNoWait(queue, ifUnused, ifEmpty); + } - /// - /// (Spec method) Unbinds a queue. - /// - public static void QueueUnbind(this IModel model, string queue, string exchange, string routingKey, IDictionary arguments = null) - { - model.QueueUnbind(queue, exchange, routingKey, arguments); - } + /// + /// (Spec method) Unbinds a queue. + /// + public static void QueueUnbind(this IModel model, string queue, string exchange, string routingKey, IDictionary arguments = null) + { + model.QueueUnbind(queue, exchange, routingKey, arguments); + } - /// - /// Abort this session. - /// - /// - /// If the session is already closed (or closing), then this - /// method does nothing but wait for the in-progress close - /// operation to complete. This method will not return to the - /// caller until the shutdown is complete. - /// In comparison to normal method, will not throw - /// or or any other during closing model. - /// - public static void Abort(this IModel model) - { - model.Close(Constants.ReplySuccess, "Goodbye", true); - } + /// + /// Abort this session. + /// + /// + /// If the session is already closed (or closing), then this + /// method does nothing but wait for the in-progress close + /// operation to complete. This method will not return to the + /// caller until the shutdown is complete. + /// In comparison to normal method, will not throw + /// or or any other during closing model. + /// + public static void Abort(this IModel model) + { + model.Close(Constants.ReplySuccess, "Goodbye", true); + } - /// - /// Abort this session. - /// - /// - /// The method behaves in the same way as , with the only - /// difference that the model is closed with the given model close code and message. - /// - /// The close code (See under "Reply Codes" in the AMQP specification) - /// - /// - /// A message indicating the reason for closing the model - /// - /// - public static void Abort(this IModel model, ushort replyCode, string replyText) - { - model.Close(replyCode, replyText, true); - } + /// + /// Abort this session. + /// + /// + /// The method behaves in the same way as , with the only + /// difference that the model is closed with the given model close code and message. + /// + /// The close code (See under "Reply Codes" in the AMQP specification) + /// + /// + /// A message indicating the reason for closing the model + /// + /// + public static void Abort(this IModel model, ushort replyCode, string replyText) + { + model.Close(replyCode, replyText, true); + } - /// Close this session. - /// - /// If the session is already closed (or closing), then this - /// method does nothing but wait for the in-progress close - /// operation to complete. This method will not return to the - /// caller until the shutdown is complete. - /// - public static void Close(this IModel model) - { - model.Close(Constants.ReplySuccess, "Goodbye", false); - } + /// Close this session. + /// + /// If the session is already closed (or closing), then this + /// method does nothing but wait for the in-progress close + /// operation to complete. This method will not return to the + /// caller until the shutdown is complete. + /// + public static void Close(this IModel model) + { + model.Close(Constants.ReplySuccess, "Goodbye", false); + } - /// Close this session. - /// - /// The method behaves in the same way as Close(), with the only - /// difference that the model is closed with the given model - /// close code and message. - /// - /// The close code (See under "Reply Codes" in the AMQP specification) - /// - /// - /// A message indicating the reason for closing the model - /// - /// - public static void Close(this IModel model, ushort replyCode, string replyText) - { - model.Close(replyCode, replyText, false); + /// Close this session. + /// + /// The method behaves in the same way as Close(), with the only + /// difference that the model is closed with the given model + /// close code and message. + /// + /// The close code (See under "Reply Codes" in the AMQP specification) + /// + /// + /// A message indicating the reason for closing the model + /// + /// + public static void Close(this IModel model, ushort replyCode, string replyText) + { + model.Close(replyCode, replyText, false); + } } } diff --git a/projects/RabbitMQ.Client/client/api/INetworkConnection.cs b/projects/RabbitMQ.Client/client/api/INetworkConnection.cs index 30af5e5362..04fdc3ff59 100644 --- a/projects/RabbitMQ.Client/client/api/INetworkConnection.cs +++ b/projects/RabbitMQ.Client/client/api/INetworkConnection.cs @@ -29,20 +29,21 @@ // Copyright (c) 2007-2020 VMware, Inc. All rights reserved. //--------------------------------------------------------------------------- -namespace RabbitMQ.Client; - -/// -/// Common interface for network (TCP/IP) connection classes. -/// -public interface INetworkConnection +namespace RabbitMQ.Client { /// - /// Local port. + /// Common interface for network (TCP/IP) connection classes. /// - int LocalPort { get; } + public interface INetworkConnection + { + /// + /// Local port. + /// + int LocalPort { get; } - /// - /// Remote port. - /// - int RemotePort { get; } + /// + /// Remote port. + /// + int RemotePort { get; } + } } diff --git a/projects/RabbitMQ.Client/client/api/IProtocol.cs b/projects/RabbitMQ.Client/client/api/IProtocol.cs index e4f8b9b98c..10897ef2a7 100644 --- a/projects/RabbitMQ.Client/client/api/IProtocol.cs +++ b/projects/RabbitMQ.Client/client/api/IProtocol.cs @@ -29,37 +29,38 @@ // Copyright (c) 2007-2020 VMware, Inc. All rights reserved. //--------------------------------------------------------------------------- -namespace RabbitMQ.Client; - -/// -/// Object describing various overarching parameters -/// associated with a particular AMQP protocol variant. -/// -public interface IProtocol +namespace RabbitMQ.Client { /// - /// Retrieve the protocol's API name, used for printing, - /// configuration properties, IDE integration, Protocols.cs etc. + /// Object describing various overarching parameters + /// associated with a particular AMQP protocol variant. /// - string ApiName { get; } + public interface IProtocol + { + /// + /// Retrieve the protocol's API name, used for printing, + /// configuration properties, IDE integration, Protocols.cs etc. + /// + string ApiName { get; } - /// - /// Retrieve the protocol's default TCP port. - /// - int DefaultPort { get; } + /// + /// Retrieve the protocol's default TCP port. + /// + int DefaultPort { get; } - /// - /// Retrieve the protocol's major version number. - /// - int MajorVersion { get; } + /// + /// Retrieve the protocol's major version number. + /// + int MajorVersion { get; } - /// - /// Retrieve the protocol's minor version number. - /// - int MinorVersion { get; } + /// + /// Retrieve the protocol's minor version number. + /// + int MinorVersion { get; } - /// - /// Retrieve the protocol's revision (if specified). - /// - int Revision { get; } + /// + /// Retrieve the protocol's revision (if specified). + /// + int Revision { get; } + } } diff --git a/projects/RabbitMQ.Client/client/api/IRecoverable.cs b/projects/RabbitMQ.Client/client/api/IRecoverable.cs index 9e987c85c1..86f086812c 100644 --- a/projects/RabbitMQ.Client/client/api/IRecoverable.cs +++ b/projects/RabbitMQ.Client/client/api/IRecoverable.cs @@ -31,12 +31,13 @@ using System; -namespace RabbitMQ.Client; - -/// -/// A marker interface for entities that are recoverable (currently connection or channel). -/// -public interface IRecoverable +namespace RabbitMQ.Client { - event EventHandler Recovery; + /// + /// A marker interface for entities that are recoverable (currently connection or channel). + /// + public interface IRecoverable + { + event EventHandler Recovery; + } } diff --git a/projects/RabbitMQ.Client/client/api/ITcpClient.cs b/projects/RabbitMQ.Client/client/api/ITcpClient.cs index ca61ce7f42..da8398dd01 100644 --- a/projects/RabbitMQ.Client/client/api/ITcpClient.cs +++ b/projects/RabbitMQ.Client/client/api/ITcpClient.cs @@ -3,24 +3,25 @@ using System.Net.Sockets; using System.Threading.Tasks; -namespace RabbitMQ.Client; - -/// -/// Wrapper interface for standard TCP-client. Provides socket for socket frame handler class. -/// -/// Contains all methods that are currently in use in rabbitmq client. -public interface ITcpClient : IDisposable +namespace RabbitMQ.Client { - bool Connected { get; } + /// + /// Wrapper interface for standard TCP-client. Provides socket for socket frame handler class. + /// + /// Contains all methods that are currently in use in rabbitmq client. + public interface ITcpClient : IDisposable + { + bool Connected { get; } - TimeSpan ReceiveTimeout { get; set; } + TimeSpan ReceiveTimeout { get; set; } - Socket Client { get; } + Socket Client { get; } - Task ConnectAsync(string host, int port); - Task ConnectAsync(IPAddress host, int port); + Task ConnectAsync(string host, int port); + Task ConnectAsync(IPAddress host, int port); - NetworkStream GetStream(); + NetworkStream GetStream(); - void Close(); + void Close(); + } } diff --git a/projects/RabbitMQ.Client/client/api/InternalConstants.cs b/projects/RabbitMQ.Client/client/api/InternalConstants.cs index b317a07bda..8ee85ae173 100644 --- a/projects/RabbitMQ.Client/client/api/InternalConstants.cs +++ b/projects/RabbitMQ.Client/client/api/InternalConstants.cs @@ -31,10 +31,11 @@ using System; -namespace RabbitMQ.Client; - -internal static class InternalConstants +namespace RabbitMQ.Client { - internal static readonly TimeSpan DefaultConnectionAbortTimeout = TimeSpan.FromSeconds(5); - internal static readonly TimeSpan DefaultConnectionCloseTimeout = TimeSpan.FromSeconds(30); + internal static class InternalConstants + { + internal static readonly TimeSpan DefaultConnectionAbortTimeout = TimeSpan.FromSeconds(5); + internal static readonly TimeSpan DefaultConnectionCloseTimeout = TimeSpan.FromSeconds(30); + } } diff --git a/projects/RabbitMQ.Client/client/api/PlainMechanism.cs b/projects/RabbitMQ.Client/client/api/PlainMechanism.cs index 5cde36768e..69bb501b08 100644 --- a/projects/RabbitMQ.Client/client/api/PlainMechanism.cs +++ b/projects/RabbitMQ.Client/client/api/PlainMechanism.cs @@ -31,12 +31,13 @@ using System.Text; -namespace RabbitMQ.Client; - -public class PlainMechanism : IAuthMechanism +namespace RabbitMQ.Client { - public byte[] handleChallenge(byte[] challenge, ConnectionConfig config) + public class PlainMechanism : IAuthMechanism { - return Encoding.UTF8.GetBytes($"\0{config.UserName}\0{config.Password}"); + public byte[] handleChallenge(byte[] challenge, ConnectionConfig config) + { + return Encoding.UTF8.GetBytes($"\0{config.UserName}\0{config.Password}"); + } } } diff --git a/projects/RabbitMQ.Client/client/api/PlainMechanismFactory.cs b/projects/RabbitMQ.Client/client/api/PlainMechanismFactory.cs index 26c9c2c09c..5da08b3eac 100644 --- a/projects/RabbitMQ.Client/client/api/PlainMechanismFactory.cs +++ b/projects/RabbitMQ.Client/client/api/PlainMechanismFactory.cs @@ -29,23 +29,24 @@ // Copyright (c) 2007-2020 VMware, Inc. All rights reserved. //--------------------------------------------------------------------------- -namespace RabbitMQ.Client; - -public class PlainMechanismFactory : IAuthMechanismFactory +namespace RabbitMQ.Client { - /// - /// The name of the authentication mechanism, as negotiated on the wire. - /// - public string Name + public class PlainMechanismFactory : IAuthMechanismFactory { - get { return "PLAIN"; } - } + /// + /// The name of the authentication mechanism, as negotiated on the wire. + /// + public string Name + { + get { return "PLAIN"; } + } - /// - /// Return a new authentication mechanism implementation. - /// - public IAuthMechanism GetInstance() - { - return new PlainMechanism(); + /// + /// Return a new authentication mechanism implementation. + /// + public IAuthMechanism GetInstance() + { + return new PlainMechanism(); + } } } diff --git a/projects/RabbitMQ.Client/client/api/Protocols.cs b/projects/RabbitMQ.Client/client/api/Protocols.cs index dd5f50854d..74b3115ec4 100644 --- a/projects/RabbitMQ.Client/client/api/Protocols.cs +++ b/projects/RabbitMQ.Client/client/api/Protocols.cs @@ -29,20 +29,21 @@ // Copyright (c) 2007-2020 VMware, Inc. All rights reserved. //--------------------------------------------------------------------------- -namespace RabbitMQ.Client; - -/// -/// Provides access to the supported implementations. -/// -public static class Protocols +namespace RabbitMQ.Client { /// - /// Protocol version 0-9-1 as modified by Pivotal. - /// - public static IProtocol AMQP_0_9_1 { get; } = new Framing.Protocol(); + /// Provides access to the supported implementations. + /// + public static class Protocols + { + /// + /// Protocol version 0-9-1 as modified by Pivotal. + /// + public static IProtocol AMQP_0_9_1 { get; } = new Framing.Protocol(); - /// - /// Retrieve the current default protocol variant (currently AMQP_0_9_1). - /// - public static IProtocol DefaultProtocol => AMQP_0_9_1; + /// + /// Retrieve the current default protocol variant (currently AMQP_0_9_1). + /// + public static IProtocol DefaultProtocol => AMQP_0_9_1; + } } diff --git a/projects/RabbitMQ.Client/client/api/PublicationAddress.cs b/projects/RabbitMQ.Client/client/api/PublicationAddress.cs index d0f72c0c77..f35863b551 100644 --- a/projects/RabbitMQ.Client/client/api/PublicationAddress.cs +++ b/projects/RabbitMQ.Client/client/api/PublicationAddress.cs @@ -31,113 +31,114 @@ using System.Text.RegularExpressions; -namespace RabbitMQ.Client; - -/// -/// Container for an exchange name, exchange type and -/// routing key, usable as the target address of a message to be published. -/// -/// -/// -/// The syntax used for the external representation of instances -/// of this class is compatible with QPid's "Reply-To" field -/// pseudo-URI format. The pseudo-URI format is -/// (exchange-type)://(exchange-name)/(routing-key), where -/// exchange-type is one of the permitted exchange type names (see -/// class ExchangeType), exchange-name must be present but may be -/// empty, and routing-key must be present but may be empty. -/// -/// -/// The syntax is as it is solely for compatibility with QPid's -/// existing usage of the ReplyTo field; the AMQP specifications -/// 0-8 and 0-9 do not define the format of the field, and do not -/// define any format for the triple (exchange name, exchange -/// type, routing key) that could be used instead. -/// -/// -public class PublicationAddress +namespace RabbitMQ.Client { /// - /// Regular expression used to extract the exchange-type, - /// exchange-name and routing-key from a string. + /// Container for an exchange name, exchange type and + /// routing key, usable as the target address of a message to be published. /// - public static readonly Regex PSEUDO_URI_PARSER = new Regex("^([^:]+)://([^/]*)/(.*)$"); - - /// - /// Creates a new instance of the . - /// - /// Exchange type. - /// Exchange name. - /// Routing key. - public PublicationAddress(string exchangeType, string exchangeName, string routingKey) + /// + /// + /// The syntax used for the external representation of instances + /// of this class is compatible with QPid's "Reply-To" field + /// pseudo-URI format. The pseudo-URI format is + /// (exchange-type)://(exchange-name)/(routing-key), where + /// exchange-type is one of the permitted exchange type names (see + /// class ExchangeType), exchange-name must be present but may be + /// empty, and routing-key must be present but may be empty. + /// + /// + /// The syntax is as it is solely for compatibility with QPid's + /// existing usage of the ReplyTo field; the AMQP specifications + /// 0-8 and 0-9 do not define the format of the field, and do not + /// define any format for the triple (exchange name, exchange + /// type, routing key) that could be used instead. + /// + /// + public class PublicationAddress { - ExchangeType = exchangeType; - ExchangeName = exchangeName; - RoutingKey = routingKey; - } + /// + /// Regular expression used to extract the exchange-type, + /// exchange-name and routing-key from a string. + /// + public static readonly Regex PSEUDO_URI_PARSER = new Regex("^([^:]+)://([^/]*)/(.*)$"); - /// - /// Retrieve the exchange name. - /// - public string ExchangeName { get; } + /// + /// Creates a new instance of the . + /// + /// Exchange type. + /// Exchange name. + /// Routing key. + public PublicationAddress(string exchangeType, string exchangeName, string routingKey) + { + ExchangeType = exchangeType; + ExchangeName = exchangeName; + RoutingKey = routingKey; + } - /// - /// Retrieve the exchange type string. - /// - public string ExchangeType { get; } + /// + /// Retrieve the exchange name. + /// + public string ExchangeName { get; } - /// - ///Retrieve the routing key. - /// - public string RoutingKey { get; } + /// + /// Retrieve the exchange type string. + /// + public string ExchangeType { get; } - /// - /// Parse a out of the given string, - /// using the regex. - /// - public static PublicationAddress Parse(string uriLikeString) - { - Match match = PSEUDO_URI_PARSER.Match(uriLikeString); - if (match.Success) - { - return new PublicationAddress(match.Groups[1].Value, - match.Groups[2].Value, - match.Groups[3].Value); - } - return null; - } + /// + ///Retrieve the routing key. + /// + public string RoutingKey { get; } - public static bool TryParse(string uriLikeString, out PublicationAddress result) - { - // Callers such as IBasicProperties.ReplyToAddress - // expect null result for invalid input. - // The regex.Match() throws on null arguments so we perform explicit check here - if (uriLikeString is null) - { - result = null; - return false; - } - else + /// + /// Parse a out of the given string, + /// using the regex. + /// + public static PublicationAddress Parse(string uriLikeString) { - try + Match match = PSEUDO_URI_PARSER.Match(uriLikeString); + if (match.Success) { - PublicationAddress res = Parse(uriLikeString); - result = res; - return true; + return new PublicationAddress(match.Groups[1].Value, + match.Groups[2].Value, + match.Groups[3].Value); } - catch + return null; + } + + public static bool TryParse(string uriLikeString, out PublicationAddress result) + { + // Callers such as IBasicProperties.ReplyToAddress + // expect null result for invalid input. + // The regex.Match() throws on null arguments so we perform explicit check here + if (uriLikeString is null) { result = null; return false; } + else + { + try + { + PublicationAddress res = Parse(uriLikeString); + result = res; + return true; + } + catch + { + result = null; + return false; + } + } } - } - /// - /// Reconstruct the "uri" from its constituents. - /// - public override string ToString() - { - return $"{ExchangeType}://{ExchangeName}/{RoutingKey}"; + /// + /// Reconstruct the "uri" from its constituents. + /// + public override string ToString() + { + return $"{ExchangeType}://{ExchangeName}/{RoutingKey}"; + } } } diff --git a/projects/RabbitMQ.Client/client/api/QueueDeclareOk.cs b/projects/RabbitMQ.Client/client/api/QueueDeclareOk.cs index 2f33aeb43a..dd20ebfa33 100644 --- a/projects/RabbitMQ.Client/client/api/QueueDeclareOk.cs +++ b/projects/RabbitMQ.Client/client/api/QueueDeclareOk.cs @@ -29,43 +29,44 @@ // Copyright (c) 2007-2020 VMware, Inc. All rights reserved. //--------------------------------------------------------------------------- -namespace RabbitMQ.Client; - -/// -/// Represents Queue info. -/// -public class QueueDeclareOk +namespace RabbitMQ.Client { /// - /// Creates a new instance of the . + /// Represents Queue info. /// - /// Queue name. - /// Message count. - /// Consumer count. - public QueueDeclareOk(string queueName, uint messageCount, uint consumerCount) + public class QueueDeclareOk { - QueueName = queueName; - MessageCount = messageCount; - ConsumerCount = consumerCount; - } + /// + /// Creates a new instance of the . + /// + /// Queue name. + /// Message count. + /// Consumer count. + public QueueDeclareOk(string queueName, uint messageCount, uint consumerCount) + { + QueueName = queueName; + MessageCount = messageCount; + ConsumerCount = consumerCount; + } - /// - /// Consumer count. - /// - public uint ConsumerCount { get; } + /// + /// Consumer count. + /// + public uint ConsumerCount { get; } - /// - /// Message count. - /// - public uint MessageCount { get; } + /// + /// Message count. + /// + public uint MessageCount { get; } - /// - /// Queue name. - /// - public string QueueName { get; } + /// + /// Queue name. + /// + public string QueueName { get; } - public static implicit operator string(QueueDeclareOk declareOk) - { - return declareOk.QueueName; + public static implicit operator string(QueueDeclareOk declareOk) + { + return declareOk.QueueName; + } } } diff --git a/projects/RabbitMQ.Client/client/api/ReadonlyBasicProperties.cs b/projects/RabbitMQ.Client/client/api/ReadonlyBasicProperties.cs index f8e5c10bd2..8b3623ef23 100644 --- a/projects/RabbitMQ.Client/client/api/ReadonlyBasicProperties.cs +++ b/projects/RabbitMQ.Client/client/api/ReadonlyBasicProperties.cs @@ -33,90 +33,91 @@ using System.Collections.Generic; using RabbitMQ.Client.Impl; -namespace RabbitMQ.Client; - -#nullable enable -/// -/// AMQP specification content header properties for content class "basic" -/// -public readonly struct ReadOnlyBasicProperties : IReadOnlyBasicProperties +namespace RabbitMQ.Client { - private readonly string? _contentType; - private readonly string? _contentEncoding; - private readonly IDictionary? _headers; - private readonly DeliveryModes _deliveryMode; - private readonly byte _priority; - private readonly string? _correlationId; - private readonly string? _replyTo; - private readonly string? _expiration; - private readonly string? _messageId; - private readonly AmqpTimestamp _timestamp; - private readonly string? _type; - private readonly string? _userId; - private readonly string? _appId; - private readonly string? _clusterId; +#nullable enable + /// + /// AMQP specification content header properties for content class "basic" + /// + public readonly struct ReadOnlyBasicProperties : IReadOnlyBasicProperties + { + private readonly string? _contentType; + private readonly string? _contentEncoding; + private readonly IDictionary? _headers; + private readonly DeliveryModes _deliveryMode; + private readonly byte _priority; + private readonly string? _correlationId; + private readonly string? _replyTo; + private readonly string? _expiration; + private readonly string? _messageId; + private readonly AmqpTimestamp _timestamp; + private readonly string? _type; + private readonly string? _userId; + private readonly string? _appId; + private readonly string? _clusterId; - public string? ContentType => _contentType; - public string? ContentEncoding => _contentEncoding; - public IDictionary? Headers => _headers; - public DeliveryModes DeliveryMode => _deliveryMode; - public byte Priority => _priority; - public string? CorrelationId => _correlationId; - public string? ReplyTo => _replyTo; - public string? Expiration => _expiration; - public string? MessageId => _messageId; - public AmqpTimestamp Timestamp => _timestamp; - public string? Type => _type; - public string? UserId => _userId; - public string? AppId => _appId; - public string? ClusterId => _clusterId; + public string? ContentType => _contentType; + public string? ContentEncoding => _contentEncoding; + public IDictionary? Headers => _headers; + public DeliveryModes DeliveryMode => _deliveryMode; + public byte Priority => _priority; + public string? CorrelationId => _correlationId; + public string? ReplyTo => _replyTo; + public string? Expiration => _expiration; + public string? MessageId => _messageId; + public AmqpTimestamp Timestamp => _timestamp; + public string? Type => _type; + public string? UserId => _userId; + public string? AppId => _appId; + public string? ClusterId => _clusterId; - public bool Persistent => DeliveryMode == DeliveryModes.Persistent; + public bool Persistent => DeliveryMode == DeliveryModes.Persistent; - public PublicationAddress? ReplyToAddress - { - get + public PublicationAddress? ReplyToAddress { - PublicationAddress.TryParse(ReplyTo, out PublicationAddress result); - return result; + get + { + PublicationAddress.TryParse(ReplyTo, out PublicationAddress result); + return result; + } } - } - public ReadOnlyBasicProperties(ReadOnlySpan span) - : this() - { - int offset = 2; - ref readonly byte bits = ref span[0]; - if (bits.IsBitSet(BasicProperties.ContentTypeBit)) { offset += WireFormatting.ReadShortstr(span.Slice(offset), out _contentType); } - if (bits.IsBitSet(BasicProperties.ContentEncodingBit)) { offset += WireFormatting.ReadShortstr(span.Slice(offset), out _contentEncoding); } - if (bits.IsBitSet(BasicProperties.HeaderBit)) { offset += WireFormatting.ReadDictionary(span.Slice(offset), out var tmpDirectory); _headers = tmpDirectory; } - if (bits.IsBitSet(BasicProperties.DeliveryModeBit)) { _deliveryMode = (DeliveryModes)span[offset++]; } - if (bits.IsBitSet(BasicProperties.PriorityBit)) { _priority = span[offset++]; } - if (bits.IsBitSet(BasicProperties.CorrelationIdBit)) { offset += WireFormatting.ReadShortstr(span.Slice(offset), out _correlationId); } - if (bits.IsBitSet(BasicProperties.ReplyToBit)) { offset += WireFormatting.ReadShortstr(span.Slice(offset), out _replyTo); } - if (bits.IsBitSet(BasicProperties.ExpirationBit)) { offset += WireFormatting.ReadShortstr(span.Slice(offset), out _expiration); } + public ReadOnlyBasicProperties(ReadOnlySpan span) + : this() + { + int offset = 2; + ref readonly byte bits = ref span[0]; + if (bits.IsBitSet(BasicProperties.ContentTypeBit)) { offset += WireFormatting.ReadShortstr(span.Slice(offset), out _contentType); } + if (bits.IsBitSet(BasicProperties.ContentEncodingBit)) { offset += WireFormatting.ReadShortstr(span.Slice(offset), out _contentEncoding); } + if (bits.IsBitSet(BasicProperties.HeaderBit)) { offset += WireFormatting.ReadDictionary(span.Slice(offset), out var tmpDirectory); _headers = tmpDirectory; } + if (bits.IsBitSet(BasicProperties.DeliveryModeBit)) { _deliveryMode = (DeliveryModes)span[offset++]; } + if (bits.IsBitSet(BasicProperties.PriorityBit)) { _priority = span[offset++]; } + if (bits.IsBitSet(BasicProperties.CorrelationIdBit)) { offset += WireFormatting.ReadShortstr(span.Slice(offset), out _correlationId); } + if (bits.IsBitSet(BasicProperties.ReplyToBit)) { offset += WireFormatting.ReadShortstr(span.Slice(offset), out _replyTo); } + if (bits.IsBitSet(BasicProperties.ExpirationBit)) { offset += WireFormatting.ReadShortstr(span.Slice(offset), out _expiration); } - bits = ref span[1]; - if (bits.IsBitSet(BasicProperties.MessageIdBit)) { offset += WireFormatting.ReadShortstr(span.Slice(offset), out _messageId); } - if (bits.IsBitSet(BasicProperties.TimestampBit)) { offset += WireFormatting.ReadTimestamp(span.Slice(offset), out _timestamp); } - if (bits.IsBitSet(BasicProperties.TypeBit)) { offset += WireFormatting.ReadShortstr(span.Slice(offset), out _type); } - if (bits.IsBitSet(BasicProperties.UserIdBit)) { offset += WireFormatting.ReadShortstr(span.Slice(offset), out _userId); } - if (bits.IsBitSet(BasicProperties.AppIdBit)) { offset += WireFormatting.ReadShortstr(span.Slice(offset), out _appId); } - if (bits.IsBitSet(BasicProperties.ClusterIdBit)) { WireFormatting.ReadShortstr(span.Slice(offset), out _clusterId); } - } + bits = ref span[1]; + if (bits.IsBitSet(BasicProperties.MessageIdBit)) { offset += WireFormatting.ReadShortstr(span.Slice(offset), out _messageId); } + if (bits.IsBitSet(BasicProperties.TimestampBit)) { offset += WireFormatting.ReadTimestamp(span.Slice(offset), out _timestamp); } + if (bits.IsBitSet(BasicProperties.TypeBit)) { offset += WireFormatting.ReadShortstr(span.Slice(offset), out _type); } + if (bits.IsBitSet(BasicProperties.UserIdBit)) { offset += WireFormatting.ReadShortstr(span.Slice(offset), out _userId); } + if (bits.IsBitSet(BasicProperties.AppIdBit)) { offset += WireFormatting.ReadShortstr(span.Slice(offset), out _appId); } + if (bits.IsBitSet(BasicProperties.ClusterIdBit)) { WireFormatting.ReadShortstr(span.Slice(offset), out _clusterId); } + } - public bool IsContentTypePresent() => ContentType != default; - public bool IsContentEncodingPresent() => ContentEncoding != default; - public bool IsHeadersPresent() => Headers != default; - public bool IsDeliveryModePresent() => DeliveryMode != default; - public bool IsPriorityPresent() => Priority != default; - public bool IsCorrelationIdPresent() => CorrelationId != default; - public bool IsReplyToPresent() => ReplyTo != default; - public bool IsExpirationPresent() => Expiration != default; - public bool IsMessageIdPresent() => MessageId != default; - public bool IsTimestampPresent() => Timestamp != default; - public bool IsTypePresent() => Type != default; - public bool IsUserIdPresent() => UserId != default; - public bool IsAppIdPresent() => AppId != default; - public bool IsClusterIdPresent() => ClusterId != default; + public bool IsContentTypePresent() => ContentType != default; + public bool IsContentEncodingPresent() => ContentEncoding != default; + public bool IsHeadersPresent() => Headers != default; + public bool IsDeliveryModePresent() => DeliveryMode != default; + public bool IsPriorityPresent() => Priority != default; + public bool IsCorrelationIdPresent() => CorrelationId != default; + public bool IsReplyToPresent() => ReplyTo != default; + public bool IsExpirationPresent() => Expiration != default; + public bool IsMessageIdPresent() => MessageId != default; + public bool IsTimestampPresent() => Timestamp != default; + public bool IsTypePresent() => Type != default; + public bool IsUserIdPresent() => UserId != default; + public bool IsAppIdPresent() => AppId != default; + public bool IsClusterIdPresent() => ClusterId != default; + } } diff --git a/projects/RabbitMQ.Client/client/api/ShutdownEventArgs.cs b/projects/RabbitMQ.Client/client/api/ShutdownEventArgs.cs index 6d7e6efdd1..cfc0c16d31 100644 --- a/projects/RabbitMQ.Client/client/api/ShutdownEventArgs.cs +++ b/projects/RabbitMQ.Client/client/api/ShutdownEventArgs.cs @@ -31,79 +31,80 @@ using System; -namespace RabbitMQ.Client; - -/// -/// Information about the reason why a particular model, session, or connection was destroyed. -/// -/// -/// The and properties should be used to determine the originator of the shutdown event. -/// -public class ShutdownEventArgs : EventArgs +namespace RabbitMQ.Client { /// - /// Construct a with the given parameters and - /// 0 for and . + /// Information about the reason why a particular model, session, or connection was destroyed. /// - public ShutdownEventArgs(ShutdownInitiator initiator, ushort replyCode, string replyText, object cause = null) - : this(initiator, replyCode, replyText, 0, 0, cause) + /// + /// The and properties should be used to determine the originator of the shutdown event. + /// + public class ShutdownEventArgs : EventArgs { - } + /// + /// Construct a with the given parameters and + /// 0 for and . + /// + public ShutdownEventArgs(ShutdownInitiator initiator, ushort replyCode, string replyText, object cause = null) + : this(initiator, replyCode, replyText, 0, 0, cause) + { + } - /// - /// Construct a with the given parameters. - /// - public ShutdownEventArgs(ShutdownInitiator initiator, ushort replyCode, string replyText, - ushort classId, ushort methodId, object cause = null) - { - Initiator = initiator; - ReplyCode = replyCode; - ReplyText = replyText; - ClassId = classId; - MethodId = methodId; - Cause = cause; - } + /// + /// Construct a with the given parameters. + /// + public ShutdownEventArgs(ShutdownInitiator initiator, ushort replyCode, string replyText, + ushort classId, ushort methodId, object cause = null) + { + Initiator = initiator; + ReplyCode = replyCode; + ReplyText = replyText; + ClassId = classId; + MethodId = methodId; + Cause = cause; + } - /// - /// Object causing the shutdown, or null if none. - /// - public object Cause { get; } + /// + /// Object causing the shutdown, or null if none. + /// + public object Cause { get; } - /// - /// AMQP content-class ID, or 0 if none. - /// - public ushort ClassId { get; } + /// + /// AMQP content-class ID, or 0 if none. + /// + public ushort ClassId { get; } - /// - /// Returns the source of the shutdown event: either the application, the library, or the remote peer. - /// - public ShutdownInitiator Initiator { get; } + /// + /// Returns the source of the shutdown event: either the application, the library, or the remote peer. + /// + public ShutdownInitiator Initiator { get; } - /// - /// AMQP method ID within a content-class, or 0 if none. - /// - public ushort MethodId { get; } + /// + /// AMQP method ID within a content-class, or 0 if none. + /// + public ushort MethodId { get; } - /// - /// One of the standardised AMQP reason codes. See RabbitMQ.Client.Framing.*.Constants. - /// - public ushort ReplyCode { get; } + /// + /// One of the standardised AMQP reason codes. See RabbitMQ.Client.Framing.*.Constants. + /// + public ushort ReplyCode { get; } - /// - /// Informative human-readable reason text. - /// - public string ReplyText { get; } + /// + /// Informative human-readable reason text. + /// + public string ReplyText { get; } - /// - /// Override ToString to be useful for debugging. - /// - public override string ToString() - { - return $"AMQP close-reason, initiated by {Initiator}" - + $", code={ReplyCode}" - + (ReplyText != null ? $", text='{ReplyText}'" : string.Empty) - + $", classId={ClassId}" - + $", methodId={MethodId}" - + (Cause != null ? $", cause={Cause}" : string.Empty); + /// + /// Override ToString to be useful for debugging. + /// + public override string ToString() + { + return $"AMQP close-reason, initiated by {Initiator}" + + $", code={ReplyCode}" + + (ReplyText != null ? $", text='{ReplyText}'" : string.Empty) + + $", classId={ClassId}" + + $", methodId={MethodId}" + + (Cause != null ? $", cause={Cause}" : string.Empty); + } } } diff --git a/projects/RabbitMQ.Client/client/api/ShutdownInitiator.cs b/projects/RabbitMQ.Client/client/api/ShutdownInitiator.cs index 32151bcf2c..2a4226e63a 100644 --- a/projects/RabbitMQ.Client/client/api/ShutdownInitiator.cs +++ b/projects/RabbitMQ.Client/client/api/ShutdownInitiator.cs @@ -29,35 +29,36 @@ // Copyright (c) 2007-2020 VMware, Inc. All rights reserved. //--------------------------------------------------------------------------- -namespace RabbitMQ.Client; - -/// -/// Describes the source of a shutdown event. -/// -public enum ShutdownInitiator +namespace RabbitMQ.Client { /// - /// The shutdown event originated from the application using the RabbitMQ .NET client library. + /// Describes the source of a shutdown event. /// - Application, + public enum ShutdownInitiator + { + /// + /// The shutdown event originated from the application using the RabbitMQ .NET client library. + /// + Application, - /// - /// The shutdown event originated from the RabbitMQ .NET client library itself. - /// - /// - /// Shutdowns with this ShutdownInitiator code may appear if, - /// for example, an internal error is detected by the client, - /// or if the server sends a syntactically invalid - /// frame. Another potential use is on IConnection AutoClose. - /// - Library, + /// + /// The shutdown event originated from the RabbitMQ .NET client library itself. + /// + /// + /// Shutdowns with this ShutdownInitiator code may appear if, + /// for example, an internal error is detected by the client, + /// or if the server sends a syntactically invalid + /// frame. Another potential use is on IConnection AutoClose. + /// + Library, - /// - /// The shutdown event originated from the remote AMQP peer. - /// - /// - /// A valid received connection.close or channel.close event - /// will manifest as a shutdown with this ShutdownInitiator. - /// - Peer -}; + /// + /// The shutdown event originated from the remote AMQP peer. + /// + /// + /// A valid received connection.close or channel.close event + /// will manifest as a shutdown with this ShutdownInitiator. + /// + Peer + }; +} diff --git a/projects/RabbitMQ.Client/client/api/ShutdownReportEntry.cs b/projects/RabbitMQ.Client/client/api/ShutdownReportEntry.cs index c1b143329f..c4935c9ed3 100644 --- a/projects/RabbitMQ.Client/client/api/ShutdownReportEntry.cs +++ b/projects/RabbitMQ.Client/client/api/ShutdownReportEntry.cs @@ -31,33 +31,34 @@ using System; -namespace RabbitMQ.Client; - -/// -/// Single entry object in the shutdown report that encapsulates description -/// of the error which occurred during shutdown. -/// -public class ShutdownReportEntry +namespace RabbitMQ.Client { - public ShutdownReportEntry(string description, Exception exception) - { - Description = description; - Exception = exception; - } - /// - /// Description provided in the error. + /// Single entry object in the shutdown report that encapsulates description + /// of the error which occurred during shutdown. /// - public string Description { get; set; } + public class ShutdownReportEntry + { + public ShutdownReportEntry(string description, Exception exception) + { + Description = description; + Exception = exception; + } - /// - /// object that occurred during shutdown, or null if unspecified. - /// - public Exception Exception { get; set; } + /// + /// Description provided in the error. + /// + public string Description { get; set; } - public override string ToString() - { - string description = $"Message: {Description}"; - return (Exception != null) ? $"{description} Exception: {Exception}" : description; + /// + /// object that occurred during shutdown, or null if unspecified. + /// + public Exception Exception { get; set; } + + public override string ToString() + { + string description = $"Message: {Description}"; + return (Exception != null) ? $"{description} Exception: {Exception}" : description; + } } } diff --git a/projects/RabbitMQ.Client/client/api/SslOption.cs b/projects/RabbitMQ.Client/client/api/SslOption.cs index feb23bfb0e..e72727c494 100644 --- a/projects/RabbitMQ.Client/client/api/SslOption.cs +++ b/projects/RabbitMQ.Client/client/api/SslOption.cs @@ -34,136 +34,137 @@ using System.Security.Authentication; using System.Security.Cryptography.X509Certificates; -namespace RabbitMQ.Client; - -/// -/// Represents a set of configurable TLS options for a connection. Use this class to configure -/// TLS version used, client certificate list or file location, peer certificate verification -/// (validation) functions, expected server name (Subject Alternative Name or Common Name), -/// and so on. -/// -public class SslOption +namespace RabbitMQ.Client { - private X509CertificateCollection _certificateCollection; - - /// - /// Constructs an specifying both the server canonical name and the client's certificate path. - /// - public SslOption(string serverName, string certificatePath = "", bool enabled = false) - { - Version = SslProtocols.None; - AcceptablePolicyErrors = SslPolicyErrors.None; - ServerName = serverName; - CertPath = certificatePath; - Enabled = enabled; - CertificateValidationCallback = null; - CertificateSelectionCallback = null; - } - /// - /// Constructs an with no parameters set. + /// Represents a set of configurable TLS options for a connection. Use this class to configure + /// TLS version used, client certificate list or file location, peer certificate verification + /// (validation) functions, expected server name (Subject Alternative Name or Common Name), + /// and so on. /// - public SslOption() - : this(string.Empty) + public class SslOption { - } - - /// - /// Retrieve or set the set of TLS policy (peer verification) errors that are deemed acceptable. - /// - public SslPolicyErrors AcceptablePolicyErrors { get; set; } - - /// - /// Retrieve or set the client certificate passphrase. - /// - public string CertPassphrase { get; set; } - - /// - /// Retrieve or set the path to client certificate. - /// - public string CertPath { get; set; } + private X509CertificateCollection _certificateCollection; - /// - /// An optional client TLS certificate selection callback. If this is not specified, - /// the first valid certificate found will be used. - /// - public LocalCertificateSelectionCallback CertificateSelectionCallback { get; set; } + /// + /// Constructs an specifying both the server canonical name and the client's certificate path. + /// + public SslOption(string serverName, string certificatePath = "", bool enabled = false) + { + Version = SslProtocols.None; + AcceptablePolicyErrors = SslPolicyErrors.None; + ServerName = serverName; + CertPath = certificatePath; + Enabled = enabled; + CertificateValidationCallback = null; + CertificateSelectionCallback = null; + } - /// - /// An optional peer verification (TLS certificate validation) callback. If this is not specified, - /// the default callback will be used in conjunction with the property to - /// determine if the peer's (server's) certificate should be considered valid (acceptable). - /// - public RemoteCertificateValidationCallback CertificateValidationCallback { get; set; } + /// + /// Constructs an with no parameters set. + /// + public SslOption() + : this(string.Empty) + { + } - /// - /// Retrieve or set the X509CertificateCollection containing the client certificate. - /// If no collection is set, the client will attempt to load one from the specified . - /// - public X509CertificateCollection Certs - { - get + /// + /// Retrieve or set the set of TLS policy (peer verification) errors that are deemed acceptable. + /// + public SslPolicyErrors AcceptablePolicyErrors { get; set; } + + /// + /// Retrieve or set the client certificate passphrase. + /// + public string CertPassphrase { get; set; } + + /// + /// Retrieve or set the path to client certificate. + /// + public string CertPath { get; set; } + + /// + /// An optional client TLS certificate selection callback. If this is not specified, + /// the first valid certificate found will be used. + /// + public LocalCertificateSelectionCallback CertificateSelectionCallback { get; set; } + + /// + /// An optional peer verification (TLS certificate validation) callback. If this is not specified, + /// the default callback will be used in conjunction with the property to + /// determine if the peer's (server's) certificate should be considered valid (acceptable). + /// + public RemoteCertificateValidationCallback CertificateValidationCallback { get; set; } + + /// + /// Retrieve or set the X509CertificateCollection containing the client certificate. + /// If no collection is set, the client will attempt to load one from the specified . + /// + public X509CertificateCollection Certs { - if (_certificateCollection != null) + get { - return _certificateCollection; + if (_certificateCollection != null) + { + return _certificateCollection; + } + if (string.IsNullOrEmpty(CertPath)) + { + return null; + } + var collection = new X509CertificateCollection + { + new X509Certificate2(CertPath, CertPassphrase) + }; + return collection; } - if (string.IsNullOrEmpty(CertPath)) - { - return null; - } - var collection = new X509CertificateCollection - { - new X509Certificate2(CertPath, CertPassphrase) - }; - return collection; + set { _certificateCollection = value; } } - set { _certificateCollection = value; } - } - - /// - /// Attempts to check certificate revocation status. Default is false. - /// Set to true to check peer certificate for revocation. - /// - /// - /// Uses the built-in .NET TLS implementation machinery for checking a certificate against - /// certificate revocation lists. - /// - public bool CheckCertificateRevocation { get; set; } - - /// - /// Controls if TLS should indeed be used. Set to false to disable TLS - /// on the connection. - /// - public bool Enabled { get; set; } - - /// - /// Retrieve or set server's expected name. - /// This MUST match the Subject Alternative Name (SAN) or CN on the peer's (server's) leaf certificate, - /// otherwise the TLS connection will fail. - /// - public string ServerName { get; set; } - - /// - /// Retrieve or set the TLS protocol version. - /// The client will let the OS pick a suitable version by using . - /// If this option is disabled, e.g.see via app context, the client will attempt to fall back - /// to TLSv1.2. - /// - /// - /// - /// - /// - public SslProtocols Version { get; set; } - /// - /// Reconfigures the instance to enable/use TLSv1.2. - /// Only used in environments where System.Security.Authentication.SslProtocols.None - /// is unavailable or effectively disabled, as reported by System.Net.ServicePointManager. - /// - internal SslProtocols UseFallbackTlsVersions() - { - Version = SslProtocols.Tls12; - return Version; + /// + /// Attempts to check certificate revocation status. Default is false. + /// Set to true to check peer certificate for revocation. + /// + /// + /// Uses the built-in .NET TLS implementation machinery for checking a certificate against + /// certificate revocation lists. + /// + public bool CheckCertificateRevocation { get; set; } + + /// + /// Controls if TLS should indeed be used. Set to false to disable TLS + /// on the connection. + /// + public bool Enabled { get; set; } + + /// + /// Retrieve or set server's expected name. + /// This MUST match the Subject Alternative Name (SAN) or CN on the peer's (server's) leaf certificate, + /// otherwise the TLS connection will fail. + /// + public string ServerName { get; set; } + + /// + /// Retrieve or set the TLS protocol version. + /// The client will let the OS pick a suitable version by using . + /// If this option is disabled, e.g.see via app context, the client will attempt to fall back + /// to TLSv1.2. + /// + /// + /// + /// + /// + public SslProtocols Version { get; set; } + + /// + /// Reconfigures the instance to enable/use TLSv1.2. + /// Only used in environments where System.Security.Authentication.SslProtocols.None + /// is unavailable or effectively disabled, as reported by System.Net.ServicePointManager. + /// + internal SslProtocols UseFallbackTlsVersions() + { + Version = SslProtocols.Tls12; + return Version; + } } } diff --git a/projects/RabbitMQ.Client/client/events/AsyncEventHandler.cs b/projects/RabbitMQ.Client/client/events/AsyncEventHandler.cs index 4db44bcfba..65786dfdf1 100644 --- a/projects/RabbitMQ.Client/client/events/AsyncEventHandler.cs +++ b/projects/RabbitMQ.Client/client/events/AsyncEventHandler.cs @@ -1,5 +1,6 @@ using System.Threading.Tasks; -namespace RabbitMQ.Client.Events; - -public delegate Task AsyncEventHandler(object sender, TEvent @event); +namespace RabbitMQ.Client.Events +{ + public delegate Task AsyncEventHandler(object sender, TEvent @event); +} diff --git a/projects/RabbitMQ.Client/client/events/AsyncEventingBasicConsumer.cs b/projects/RabbitMQ.Client/client/events/AsyncEventingBasicConsumer.cs index 0e0512c9e8..ac83df6b25 100644 --- a/projects/RabbitMQ.Client/client/events/AsyncEventingBasicConsumer.cs +++ b/projects/RabbitMQ.Client/client/events/AsyncEventingBasicConsumer.cs @@ -2,88 +2,89 @@ using System.Threading.Tasks; using RabbitMQ.Client.Impl; -namespace RabbitMQ.Client.Events; - -public class AsyncEventingBasicConsumer : AsyncDefaultBasicConsumer +namespace RabbitMQ.Client.Events { - ///Constructor which sets the Model property to the given value. - public AsyncEventingBasicConsumer(IModel model) : base(model) + public class AsyncEventingBasicConsumer : AsyncDefaultBasicConsumer { - } + ///Constructor which sets the Model property to the given value. + public AsyncEventingBasicConsumer(IModel model) : base(model) + { + } - /// - /// Event fired when a delivery arrives for the consumer. - /// - /// - /// Handlers must copy or fully use delivery body before returning. - /// Accessing the body at a later point is unsafe as its memory can - /// be already released. - /// - public event AsyncEventHandler Received - { - add => _receivedWrapper.AddHandler(value); - remove => _receivedWrapper.RemoveHandler(value); - } - private AsyncEventingWrapper _receivedWrapper; + /// + /// Event fired when a delivery arrives for the consumer. + /// + /// + /// Handlers must copy or fully use delivery body before returning. + /// Accessing the body at a later point is unsafe as its memory can + /// be already released. + /// + public event AsyncEventHandler Received + { + add => _receivedWrapper.AddHandler(value); + remove => _receivedWrapper.RemoveHandler(value); + } + private AsyncEventingWrapper _receivedWrapper; - ///Fires when the server confirms successful consumer registration. - public event AsyncEventHandler Registered - { - add => _registeredWrapper.AddHandler(value); - remove => _registeredWrapper.RemoveHandler(value); - } - private AsyncEventingWrapper _registeredWrapper; + ///Fires when the server confirms successful consumer registration. + public event AsyncEventHandler Registered + { + add => _registeredWrapper.AddHandler(value); + remove => _registeredWrapper.RemoveHandler(value); + } + private AsyncEventingWrapper _registeredWrapper; - ///Fires on channel shutdown, both client and server initiated. - public event AsyncEventHandler Shutdown - { - add => _shutdownWrapper.AddHandler(value); - remove => _shutdownWrapper.RemoveHandler(value); - } - private AsyncEventingWrapper _shutdownWrapper; + ///Fires on channel shutdown, both client and server initiated. + public event AsyncEventHandler Shutdown + { + add => _shutdownWrapper.AddHandler(value); + remove => _shutdownWrapper.RemoveHandler(value); + } + private AsyncEventingWrapper _shutdownWrapper; - ///Fires when the server confirms successful consumer cancellation. - public event AsyncEventHandler Unregistered - { - add => _unregisteredWrapper.AddHandler(value); - remove => _unregisteredWrapper.RemoveHandler(value); - } - private AsyncEventingWrapper _unregisteredWrapper; + ///Fires when the server confirms successful consumer cancellation. + public event AsyncEventHandler Unregistered + { + add => _unregisteredWrapper.AddHandler(value); + remove => _unregisteredWrapper.RemoveHandler(value); + } + private AsyncEventingWrapper _unregisteredWrapper; - ///Fires when the server confirms successful consumer cancellation. - public override async Task HandleBasicCancelOk(string consumerTag) - { - await base.HandleBasicCancelOk(consumerTag).ConfigureAwait(false); - if (!_unregisteredWrapper.IsEmpty) + ///Fires when the server confirms successful consumer cancellation. + public override async Task HandleBasicCancelOk(string consumerTag) { - await _unregisteredWrapper.InvokeAsync(this, new ConsumerEventArgs(new[] { consumerTag })).ConfigureAwait(false); + await base.HandleBasicCancelOk(consumerTag).ConfigureAwait(false); + if (!_unregisteredWrapper.IsEmpty) + { + await _unregisteredWrapper.InvokeAsync(this, new ConsumerEventArgs(new[] { consumerTag })).ConfigureAwait(false); + } } - } - ///Fires when the server confirms successful consumer registration. - public override async Task HandleBasicConsumeOk(string consumerTag) - { - await base.HandleBasicConsumeOk(consumerTag).ConfigureAwait(false); - if (!_registeredWrapper.IsEmpty) + ///Fires when the server confirms successful consumer registration. + public override async Task HandleBasicConsumeOk(string consumerTag) { - await _registeredWrapper.InvokeAsync(this, new ConsumerEventArgs(new[] { consumerTag })).ConfigureAwait(false); + await base.HandleBasicConsumeOk(consumerTag).ConfigureAwait(false); + if (!_registeredWrapper.IsEmpty) + { + await _registeredWrapper.InvokeAsync(this, new ConsumerEventArgs(new[] { consumerTag })).ConfigureAwait(false); + } } - } - ///Fires the Received event. - public override Task HandleBasicDeliver(string consumerTag, ulong deliveryTag, bool redelivered, string exchange, string routingKey, in ReadOnlyBasicProperties properties, ReadOnlyMemory body) - { - // No need to call base, it's empty. - return _receivedWrapper.InvokeAsync(this, new BasicDeliverEventArgs(consumerTag, deliveryTag, redelivered, exchange, routingKey, properties, body)); - } + ///Fires the Received event. + public override Task HandleBasicDeliver(string consumerTag, ulong deliveryTag, bool redelivered, string exchange, string routingKey, in ReadOnlyBasicProperties properties, ReadOnlyMemory body) + { + // No need to call base, it's empty. + return _receivedWrapper.InvokeAsync(this, new BasicDeliverEventArgs(consumerTag, deliveryTag, redelivered, exchange, routingKey, properties, body)); + } - ///Fires the Shutdown event. - public override async Task HandleModelShutdown(object model, ShutdownEventArgs reason) - { - await base.HandleModelShutdown(model, reason).ConfigureAwait(false); - if (!_shutdownWrapper.IsEmpty) + ///Fires the Shutdown event. + public override async Task HandleModelShutdown(object model, ShutdownEventArgs reason) { - await _shutdownWrapper.InvokeAsync(this, reason).ConfigureAwait(false); + await base.HandleModelShutdown(model, reason).ConfigureAwait(false); + if (!_shutdownWrapper.IsEmpty) + { + await _shutdownWrapper.InvokeAsync(this, reason).ConfigureAwait(false); + } } } } diff --git a/projects/RabbitMQ.Client/client/events/BasicAckEventArgs.cs b/projects/RabbitMQ.Client/client/events/BasicAckEventArgs.cs index 30a892b8ae..8783e5cc14 100644 --- a/projects/RabbitMQ.Client/client/events/BasicAckEventArgs.cs +++ b/projects/RabbitMQ.Client/client/events/BasicAckEventArgs.cs @@ -31,18 +31,19 @@ using System; -namespace RabbitMQ.Client.Events; - -///Contains all the information about a message acknowledged -///from an AMQP broker within the Basic content-class. -public class BasicAckEventArgs : EventArgs +namespace RabbitMQ.Client.Events { - ///The sequence number of the acknowledged message, or - ///the closed upper bound of acknowledged messages if multiple - ///is true. - public ulong DeliveryTag { get; set; } + ///Contains all the information about a message acknowledged + ///from an AMQP broker within the Basic content-class. + public class BasicAckEventArgs : EventArgs + { + ///The sequence number of the acknowledged message, or + ///the closed upper bound of acknowledged messages if multiple + ///is true. + public ulong DeliveryTag { get; set; } - ///Whether this acknowledgement applies to one message - ///or multiple messages. - public bool Multiple { get; set; } + ///Whether this acknowledgement applies to one message + ///or multiple messages. + public bool Multiple { get; set; } + } } diff --git a/projects/RabbitMQ.Client/client/events/BasicDeliverEventArgs.cs b/projects/RabbitMQ.Client/client/events/BasicDeliverEventArgs.cs index 9c5c93c4db..96e90f4cdf 100644 --- a/projects/RabbitMQ.Client/client/events/BasicDeliverEventArgs.cs +++ b/projects/RabbitMQ.Client/client/events/BasicDeliverEventArgs.cs @@ -31,58 +31,59 @@ using System; -namespace RabbitMQ.Client.Events; - -///Contains all the information about a message delivered -///from an AMQP broker within the Basic content-class. -public class BasicDeliverEventArgs : EventArgs +namespace RabbitMQ.Client.Events { - ///Default constructor. - public BasicDeliverEventArgs() + ///Contains all the information about a message delivered + ///from an AMQP broker within the Basic content-class. + public class BasicDeliverEventArgs : EventArgs { - } + ///Default constructor. + public BasicDeliverEventArgs() + { + } - ///Constructor that fills the event's properties from - ///its arguments. - public BasicDeliverEventArgs(string consumerTag, - ulong deliveryTag, - bool redelivered, - string exchange, - string routingKey, - in ReadOnlyBasicProperties properties, - ReadOnlyMemory body) - { - ConsumerTag = consumerTag; - DeliveryTag = deliveryTag; - Redelivered = redelivered; - Exchange = exchange; - RoutingKey = routingKey; - BasicProperties = properties; - Body = body; - } + ///Constructor that fills the event's properties from + ///its arguments. + public BasicDeliverEventArgs(string consumerTag, + ulong deliveryTag, + bool redelivered, + string exchange, + string routingKey, + in ReadOnlyBasicProperties properties, + ReadOnlyMemory body) + { + ConsumerTag = consumerTag; + DeliveryTag = deliveryTag; + Redelivered = redelivered; + Exchange = exchange; + RoutingKey = routingKey; + BasicProperties = properties; + Body = body; + } - ///The content header of the message. - public ReadOnlyBasicProperties BasicProperties { get; set; } + ///The content header of the message. + public ReadOnlyBasicProperties BasicProperties { get; set; } - ///The message body. - public ReadOnlyMemory Body { get; set; } + ///The message body. + public ReadOnlyMemory Body { get; set; } - ///The consumer tag of the consumer that the message - ///was delivered to. - public string ConsumerTag { get; set; } + ///The consumer tag of the consumer that the message + ///was delivered to. + public string ConsumerTag { get; set; } - ///The delivery tag for this delivery. See - ///IModel.BasicAck. - public ulong DeliveryTag { get; set; } + ///The delivery tag for this delivery. See + ///IModel.BasicAck. + public ulong DeliveryTag { get; set; } - ///The exchange the message was originally published - ///to. - public string Exchange { get; set; } + ///The exchange the message was originally published + ///to. + public string Exchange { get; set; } - ///The AMQP "redelivered" flag. - public bool Redelivered { get; set; } + ///The AMQP "redelivered" flag. + public bool Redelivered { get; set; } - ///The routing key used when the message was - ///originally published. - public string RoutingKey { get; set; } + ///The routing key used when the message was + ///originally published. + public string RoutingKey { get; set; } + } } diff --git a/projects/RabbitMQ.Client/client/events/BasicNackEventArgs.cs b/projects/RabbitMQ.Client/client/events/BasicNackEventArgs.cs index 80b7f398b7..4c6b863e91 100644 --- a/projects/RabbitMQ.Client/client/events/BasicNackEventArgs.cs +++ b/projects/RabbitMQ.Client/client/events/BasicNackEventArgs.cs @@ -31,22 +31,23 @@ using System; -namespace RabbitMQ.Client.Events; - -///Contains all the information about a message nack'd -///from an AMQP broker within the Basic content-class. -public class BasicNackEventArgs : EventArgs +namespace RabbitMQ.Client.Events { - ///The sequence number of the nack'd message, or the - ///closed upper bound of nack'd messages if multiple is - ///true. - public ulong DeliveryTag { get; set; } + ///Contains all the information about a message nack'd + ///from an AMQP broker within the Basic content-class. + public class BasicNackEventArgs : EventArgs + { + ///The sequence number of the nack'd message, or the + ///closed upper bound of nack'd messages if multiple is + ///true. + public ulong DeliveryTag { get; set; } - ///Whether this nack applies to one message or - ///multiple messages. - public bool Multiple { get; set; } + ///Whether this nack applies to one message or + ///multiple messages. + public bool Multiple { get; set; } - ///Ignore - ///Clients should ignore this field. - public bool Requeue { get; set; } + ///Ignore + ///Clients should ignore this field. + public bool Requeue { get; set; } + } } diff --git a/projects/RabbitMQ.Client/client/events/BasicReturnEventArgs.cs b/projects/RabbitMQ.Client/client/events/BasicReturnEventArgs.cs index 80b0ff81fe..67220f1244 100644 --- a/projects/RabbitMQ.Client/client/events/BasicReturnEventArgs.cs +++ b/projects/RabbitMQ.Client/client/events/BasicReturnEventArgs.cs @@ -31,31 +31,32 @@ using System; -namespace RabbitMQ.Client.Events; - -///Contains all the information about a message returned -///from an AMQP broker within the Basic content-class. -public class BasicReturnEventArgs : EventArgs +namespace RabbitMQ.Client.Events { - ///The content header of the message. - public ReadOnlyBasicProperties BasicProperties { get; set; } - - ///The message body. - public ReadOnlyMemory Body { get; set; } - - ///The exchange the returned message was originally - ///published to. - public string Exchange { get; set; } - - ///The AMQP reason code for the return. See - ///RabbitMQ.Client.Framing.*.Constants. - public ushort ReplyCode { get; set; } - - ///Human-readable text from the broker describing the - ///reason for the return. - public string ReplyText { get; set; } - - ///The routing key used when the message was - ///originally published. - public string RoutingKey { get; set; } + ///Contains all the information about a message returned + ///from an AMQP broker within the Basic content-class. + public class BasicReturnEventArgs : EventArgs + { + ///The content header of the message. + public ReadOnlyBasicProperties BasicProperties { get; set; } + + ///The message body. + public ReadOnlyMemory Body { get; set; } + + ///The exchange the returned message was originally + ///published to. + public string Exchange { get; set; } + + ///The AMQP reason code for the return. See + ///RabbitMQ.Client.Framing.*.Constants. + public ushort ReplyCode { get; set; } + + ///Human-readable text from the broker describing the + ///reason for the return. + public string ReplyText { get; set; } + + ///The routing key used when the message was + ///originally published. + public string RoutingKey { get; set; } + } } diff --git a/projects/RabbitMQ.Client/client/events/CallbackExceptionEventArgs.cs b/projects/RabbitMQ.Client/client/events/CallbackExceptionEventArgs.cs index b4ed61ec9f..5b7d193d0c 100644 --- a/projects/RabbitMQ.Client/client/events/CallbackExceptionEventArgs.cs +++ b/projects/RabbitMQ.Client/client/events/CallbackExceptionEventArgs.cs @@ -32,72 +32,73 @@ using System; using System.Collections.Generic; -namespace RabbitMQ.Client.Events; - -public abstract class BaseExceptionEventArgs : EventArgs +namespace RabbitMQ.Client.Events { - ///Wrap an exception thrown by a callback. - protected BaseExceptionEventArgs(IDictionary detail, Exception exception) + public abstract class BaseExceptionEventArgs : EventArgs { - Detail = detail; - Exception = exception; - } + ///Wrap an exception thrown by a callback. + protected BaseExceptionEventArgs(IDictionary detail, Exception exception) + { + Detail = detail; + Exception = exception; + } - ///Access helpful information about the context in - ///which the wrapped exception was thrown. - public IDictionary Detail { get; } - - ///Access the wrapped exception. - public Exception Exception { get; } -} + ///Access helpful information about the context in + ///which the wrapped exception was thrown. + public IDictionary Detail { get; } + ///Access the wrapped exception. + public Exception Exception { get; } + } -///Describes an exception that was thrown during the -///library's invocation of an application-supplied callback -///handler. -/// -/// -/// When an exception is thrown from a callback registered with -/// part of the RabbitMQ .NET client library, it is caught, -/// packaged into a CallbackExceptionEventArgs, and passed through -/// the appropriate IModel's or IConnection's CallbackException -/// event handlers. If an exception is thrown in a -/// CallbackException handler, it is silently swallowed, as -/// CallbackException is the last chance to handle these kinds of -/// exception. -/// -/// -/// Code constructing CallbackExceptionEventArgs instances will -/// usually place helpful information about the context of the -/// call in the IDictionary available through the Detail property. -/// -/// -public class CallbackExceptionEventArgs : BaseExceptionEventArgs -{ - private const string ContextString = "context"; - private const string ConsumerString = "consumer"; - public CallbackExceptionEventArgs(IDictionary detail, Exception exception) - : base(detail, exception) + ///Describes an exception that was thrown during the + ///library's invocation of an application-supplied callback + ///handler. + /// + /// + /// When an exception is thrown from a callback registered with + /// part of the RabbitMQ .NET client library, it is caught, + /// packaged into a CallbackExceptionEventArgs, and passed through + /// the appropriate IModel's or IConnection's CallbackException + /// event handlers. If an exception is thrown in a + /// CallbackException handler, it is silently swallowed, as + /// CallbackException is the last chance to handle these kinds of + /// exception. + /// + /// + /// Code constructing CallbackExceptionEventArgs instances will + /// usually place helpful information about the context of the + /// call in the IDictionary available through the Detail property. + /// + /// + public class CallbackExceptionEventArgs : BaseExceptionEventArgs { - } + private const string ContextString = "context"; + private const string ConsumerString = "consumer"; - public static CallbackExceptionEventArgs Build(Exception e, string context) - { - var details = new Dictionary(1) + public CallbackExceptionEventArgs(IDictionary detail, Exception exception) + : base(detail, exception) { - {ContextString, context} - }; - return new CallbackExceptionEventArgs(details, e); - } + } - public static CallbackExceptionEventArgs Build(Exception e, string context, object consumer) - { - var details = new Dictionary(2) + public static CallbackExceptionEventArgs Build(Exception e, string context) + { + var details = new Dictionary(1) + { + {ContextString, context} + }; + return new CallbackExceptionEventArgs(details, e); + } + + public static CallbackExceptionEventArgs Build(Exception e, string context, object consumer) { - {ContextString, context}, - {ConsumerString, consumer} - }; - return new CallbackExceptionEventArgs(details, e); + var details = new Dictionary(2) + { + {ContextString, context}, + {ConsumerString, consumer} + }; + return new CallbackExceptionEventArgs(details, e); + } } } diff --git a/projects/RabbitMQ.Client/client/events/ConnectionBlockedEventArgs.cs b/projects/RabbitMQ.Client/client/events/ConnectionBlockedEventArgs.cs index e9c0530efb..ca8ef8aeea 100644 --- a/projects/RabbitMQ.Client/client/events/ConnectionBlockedEventArgs.cs +++ b/projects/RabbitMQ.Client/client/events/ConnectionBlockedEventArgs.cs @@ -31,20 +31,21 @@ using System; -namespace RabbitMQ.Client.Events; - -/// -/// Event relating to connection being blocked. -/// -public class ConnectionBlockedEventArgs : EventArgs +namespace RabbitMQ.Client.Events { - public ConnectionBlockedEventArgs(string reason) - { - Reason = reason; - } - /// - /// Access the reason why connection is blocked. + /// Event relating to connection being blocked. /// - public string Reason { get; } + public class ConnectionBlockedEventArgs : EventArgs + { + public ConnectionBlockedEventArgs(string reason) + { + Reason = reason; + } + + /// + /// Access the reason why connection is blocked. + /// + public string Reason { get; } + } } diff --git a/projects/RabbitMQ.Client/client/events/ConnectionRecoveryErrorEventArgs.cs b/projects/RabbitMQ.Client/client/events/ConnectionRecoveryErrorEventArgs.cs index b035f4e730..2d6284c102 100644 --- a/projects/RabbitMQ.Client/client/events/ConnectionRecoveryErrorEventArgs.cs +++ b/projects/RabbitMQ.Client/client/events/ConnectionRecoveryErrorEventArgs.cs @@ -31,14 +31,15 @@ using System; -namespace RabbitMQ.Client.Events; - -public sealed class ConnectionRecoveryErrorEventArgs : EventArgs +namespace RabbitMQ.Client.Events { - public ConnectionRecoveryErrorEventArgs(Exception ex) + public sealed class ConnectionRecoveryErrorEventArgs : EventArgs { - Exception = ex; - } + public ConnectionRecoveryErrorEventArgs(Exception ex) + { + Exception = ex; + } - public Exception Exception { get; } + public Exception Exception { get; } + } } diff --git a/projects/RabbitMQ.Client/client/events/ConsumerEventArgs.cs b/projects/RabbitMQ.Client/client/events/ConsumerEventArgs.cs index aa5264134d..9669a8b81e 100644 --- a/projects/RabbitMQ.Client/client/events/ConsumerEventArgs.cs +++ b/projects/RabbitMQ.Client/client/events/ConsumerEventArgs.cs @@ -31,20 +31,21 @@ using System; -namespace RabbitMQ.Client.Events; - -///Event relating to a successful consumer registration -///or cancellation. -public class ConsumerEventArgs : EventArgs +namespace RabbitMQ.Client.Events { - ///Construct an event containing the consumer-tags of - ///the consumer the event relates to. - public ConsumerEventArgs(string[] consumerTags) + ///Event relating to a successful consumer registration + ///or cancellation. + public class ConsumerEventArgs : EventArgs { - ConsumerTags = consumerTags; - } + ///Construct an event containing the consumer-tags of + ///the consumer the event relates to. + public ConsumerEventArgs(string[] consumerTags) + { + ConsumerTags = consumerTags; + } - ///Access the consumer-tags of the consumer the event - ///relates to. - public string[] ConsumerTags { get; } + ///Access the consumer-tags of the consumer the event + ///relates to. + public string[] ConsumerTags { get; } + } } diff --git a/projects/RabbitMQ.Client/client/events/ConsumerTagChangedAfterRecoveryEventArgs.cs b/projects/RabbitMQ.Client/client/events/ConsumerTagChangedAfterRecoveryEventArgs.cs index 5a7dfc169c..10e88cd6d6 100644 --- a/projects/RabbitMQ.Client/client/events/ConsumerTagChangedAfterRecoveryEventArgs.cs +++ b/projects/RabbitMQ.Client/client/events/ConsumerTagChangedAfterRecoveryEventArgs.cs @@ -31,28 +31,29 @@ using System; -namespace RabbitMQ.Client.Events; - -public sealed class ConsumerTagChangedAfterRecoveryEventArgs : EventArgs +namespace RabbitMQ.Client.Events { - /// - /// Initializes a new instance of the class. - /// - /// The tag before. - /// The tag after. - public ConsumerTagChangedAfterRecoveryEventArgs(string tagBefore, string tagAfter) + public sealed class ConsumerTagChangedAfterRecoveryEventArgs : EventArgs { - TagBefore = tagBefore; - TagAfter = tagAfter; - } + /// + /// Initializes a new instance of the class. + /// + /// The tag before. + /// The tag after. + public ConsumerTagChangedAfterRecoveryEventArgs(string tagBefore, string tagAfter) + { + TagBefore = tagBefore; + TagAfter = tagAfter; + } - /// - /// Gets the tag before. - /// - public string TagBefore { get; } + /// + /// Gets the tag before. + /// + public string TagBefore { get; } - /// - /// Gets the tag after. - /// - public string TagAfter { get; } + /// + /// Gets the tag after. + /// + public string TagAfter { get; } + } } diff --git a/projects/RabbitMQ.Client/client/events/EventingBasicConsumer.cs b/projects/RabbitMQ.Client/client/events/EventingBasicConsumer.cs index 8bb3dbb884..842ce37a11 100644 --- a/projects/RabbitMQ.Client/client/events/EventingBasicConsumer.cs +++ b/projects/RabbitMQ.Client/client/events/EventingBasicConsumer.cs @@ -31,71 +31,72 @@ using System; -namespace RabbitMQ.Client.Events; - -///Class exposing an IBasicConsumer's -///methods as separate events. -public class EventingBasicConsumer : DefaultBasicConsumer +namespace RabbitMQ.Client.Events { - ///Constructor which sets the Model property to the - ///given value. - public EventingBasicConsumer(IModel model) : base(model) + ///Class exposing an IBasicConsumer's + ///methods as separate events. + public class EventingBasicConsumer : DefaultBasicConsumer { - } + ///Constructor which sets the Model property to the + ///given value. + public EventingBasicConsumer(IModel model) : base(model) + { + } - /// - /// Event fired when a delivery arrives for the consumer. - /// - /// - /// Handlers must copy or fully use delivery body before returning. - /// Accessing the body at a later point is unsafe as its memory can - /// be already released. - /// - public event EventHandler Received; + /// + /// Event fired when a delivery arrives for the consumer. + /// + /// + /// Handlers must copy or fully use delivery body before returning. + /// Accessing the body at a later point is unsafe as its memory can + /// be already released. + /// + public event EventHandler Received; - ///Fires when the server confirms successful consumer registration. - public event EventHandler Registered; + ///Fires when the server confirms successful consumer registration. + public event EventHandler Registered; - ///Fires on model (channel) shutdown, both client and server initiated. - public event EventHandler Shutdown; + ///Fires on model (channel) shutdown, both client and server initiated. + public event EventHandler Shutdown; - ///Fires when the server confirms successful consumer cancellation. - public event EventHandler Unregistered; + ///Fires when the server confirms successful consumer cancellation. + public event EventHandler Unregistered; - ///Fires when the server confirms successful consumer cancellation. - public override void HandleBasicCancelOk(string consumerTag) - { - base.HandleBasicCancelOk(consumerTag); - Unregistered?.Invoke(this, new ConsumerEventArgs(new[] { consumerTag })); - } + ///Fires when the server confirms successful consumer cancellation. + public override void HandleBasicCancelOk(string consumerTag) + { + base.HandleBasicCancelOk(consumerTag); + Unregistered?.Invoke(this, new ConsumerEventArgs(new[] { consumerTag })); + } - ///Fires when the server confirms successful consumer cancellation. - public override void HandleBasicConsumeOk(string consumerTag) - { - base.HandleBasicConsumeOk(consumerTag); - Registered?.Invoke(this, new ConsumerEventArgs(new[] { consumerTag })); - } + ///Fires when the server confirms successful consumer cancellation. + public override void HandleBasicConsumeOk(string consumerTag) + { + base.HandleBasicConsumeOk(consumerTag); + Registered?.Invoke(this, new ConsumerEventArgs(new[] { consumerTag })); + } - /// - /// Invoked when a delivery arrives for the consumer. - /// - /// - /// Handlers must copy or fully use delivery body before returning. - /// Accessing the body at a later point is unsafe as its memory can - /// be already released. - /// - public override void HandleBasicDeliver(string consumerTag, ulong deliveryTag, bool redelivered, string exchange, string routingKey, in ReadOnlyBasicProperties properties, ReadOnlyMemory body) - { - base.HandleBasicDeliver(consumerTag, deliveryTag, redelivered, exchange, routingKey, properties, body); - Received?.Invoke( - this, - new BasicDeliverEventArgs(consumerTag, deliveryTag, redelivered, exchange, routingKey, properties, body)); - } + /// + /// Invoked when a delivery arrives for the consumer. + /// + /// + /// Handlers must copy or fully use delivery body before returning. + /// Accessing the body at a later point is unsafe as its memory can + /// be already released. + /// + public override void HandleBasicDeliver(string consumerTag, ulong deliveryTag, bool redelivered, string exchange, string routingKey, in ReadOnlyBasicProperties properties, ReadOnlyMemory body) + { + base.HandleBasicDeliver(consumerTag, deliveryTag, redelivered, exchange, routingKey, properties, body); + Received?.Invoke( + this, + new BasicDeliverEventArgs(consumerTag, deliveryTag, redelivered, exchange, routingKey, properties, body)); + } - ///Fires the Shutdown event. - public override void HandleModelShutdown(object model, ShutdownEventArgs reason) - { - base.HandleModelShutdown(model, reason); - Shutdown?.Invoke(this, reason); + ///Fires the Shutdown event. + public override void HandleModelShutdown(object model, ShutdownEventArgs reason) + { + base.HandleModelShutdown(model, reason); + Shutdown?.Invoke(this, reason); + } } } diff --git a/projects/RabbitMQ.Client/client/events/FlowControlEventArgs.cs b/projects/RabbitMQ.Client/client/events/FlowControlEventArgs.cs index 0892ffa848..b8c95a218f 100644 --- a/projects/RabbitMQ.Client/client/events/FlowControlEventArgs.cs +++ b/projects/RabbitMQ.Client/client/events/FlowControlEventArgs.cs @@ -31,20 +31,21 @@ using System; -namespace RabbitMQ.Client.Events; - -/// -/// Event relating to flow control. -/// -public class FlowControlEventArgs : EventArgs +namespace RabbitMQ.Client.Events { - public FlowControlEventArgs(bool active) - { - Active = active; - } - /// - /// Access the flow control setting. + /// Event relating to flow control. /// - public bool Active { get; } + public class FlowControlEventArgs : EventArgs + { + public FlowControlEventArgs(bool active) + { + Active = active; + } + + /// + /// Access the flow control setting. + /// + public bool Active { get; } + } } diff --git a/projects/RabbitMQ.Client/client/events/QueueNameChangedAfterRecoveryEventArgs.cs b/projects/RabbitMQ.Client/client/events/QueueNameChangedAfterRecoveryEventArgs.cs index 478d815fbb..ead403354f 100644 --- a/projects/RabbitMQ.Client/client/events/QueueNameChangedAfterRecoveryEventArgs.cs +++ b/projects/RabbitMQ.Client/client/events/QueueNameChangedAfterRecoveryEventArgs.cs @@ -31,28 +31,29 @@ using System; -namespace RabbitMQ.Client.Events; - -public sealed class QueueNameChangedAfterRecoveryEventArgs : EventArgs +namespace RabbitMQ.Client.Events { - /// - /// Initializes a new instance of the class. - /// - /// The name before. - /// The name after. - public QueueNameChangedAfterRecoveryEventArgs(string nameBefore, string nameAfter) + public sealed class QueueNameChangedAfterRecoveryEventArgs : EventArgs { - NameBefore = nameBefore; - NameAfter = nameAfter; - } + /// + /// Initializes a new instance of the class. + /// + /// The name before. + /// The name after. + public QueueNameChangedAfterRecoveryEventArgs(string nameBefore, string nameAfter) + { + NameBefore = nameBefore; + NameAfter = nameAfter; + } - /// - /// Gets the name before. - /// - public string NameBefore { get; } + /// + /// Gets the name before. + /// + public string NameBefore { get; } - /// - /// Gets the name after. - /// - public string NameAfter { get; } + /// + /// Gets the name after. + /// + public string NameAfter { get; } + } } diff --git a/projects/RabbitMQ.Client/client/exceptions/AlreadyClosedException.cs b/projects/RabbitMQ.Client/client/exceptions/AlreadyClosedException.cs index c5bd556b24..43776cb61d 100644 --- a/projects/RabbitMQ.Client/client/exceptions/AlreadyClosedException.cs +++ b/projects/RabbitMQ.Client/client/exceptions/AlreadyClosedException.cs @@ -31,18 +31,19 @@ using System; -namespace RabbitMQ.Client.Exceptions; - -/// Thrown when the application tries to make use of a -/// session or connection that has already been shut -/// down. -[Serializable] -public class AlreadyClosedException : OperationInterruptedException +namespace RabbitMQ.Client.Exceptions { - ///Construct an instance containing the given - ///shutdown reason. - public AlreadyClosedException(ShutdownEventArgs reason) - : base(reason, "Already closed") + /// Thrown when the application tries to make use of a + /// session or connection that has already been shut + /// down. + [Serializable] + public class AlreadyClosedException : OperationInterruptedException { + ///Construct an instance containing the given + ///shutdown reason. + public AlreadyClosedException(ShutdownEventArgs reason) + : base(reason, "Already closed") + { + } } } diff --git a/projects/RabbitMQ.Client/client/exceptions/AuthenticationFailureException.cs b/projects/RabbitMQ.Client/client/exceptions/AuthenticationFailureException.cs index 01def7a1ae..7b04d7d42a 100644 --- a/projects/RabbitMQ.Client/client/exceptions/AuthenticationFailureException.cs +++ b/projects/RabbitMQ.Client/client/exceptions/AuthenticationFailureException.cs @@ -31,14 +31,15 @@ using System; -namespace RabbitMQ.Client.Exceptions; - -/// Thrown when the cause is an -/// authentication failure. -[Serializable] -public class AuthenticationFailureException : PossibleAuthenticationFailureException +namespace RabbitMQ.Client.Exceptions { - public AuthenticationFailureException(string msg) : base(msg) + /// Thrown when the cause is an + /// authentication failure. + [Serializable] + public class AuthenticationFailureException : PossibleAuthenticationFailureException { + public AuthenticationFailureException(string msg) : base(msg) + { + } } } diff --git a/projects/RabbitMQ.Client/client/exceptions/BrokerUnreachableException.cs b/projects/RabbitMQ.Client/client/exceptions/BrokerUnreachableException.cs index a776f8fbd8..ab80e25702 100644 --- a/projects/RabbitMQ.Client/client/exceptions/BrokerUnreachableException.cs +++ b/projects/RabbitMQ.Client/client/exceptions/BrokerUnreachableException.cs @@ -32,17 +32,18 @@ using System; using System.IO; -namespace RabbitMQ.Client.Exceptions; - -///Thrown when no connection could be opened during a -///ConnectionFactory.CreateConnection attempt. -[Serializable] -public class BrokerUnreachableException : IOException +namespace RabbitMQ.Client.Exceptions { - ///Construct a BrokerUnreachableException. The inner exception is - ///an AggregateException holding the errors from multiple connection attempts. - public BrokerUnreachableException(Exception Inner) - : base("None of the specified endpoints were reachable", Inner) + ///Thrown when no connection could be opened during a + ///ConnectionFactory.CreateConnection attempt. + [Serializable] + public class BrokerUnreachableException : IOException { + ///Construct a BrokerUnreachableException. The inner exception is + ///an AggregateException holding the errors from multiple connection attempts. + public BrokerUnreachableException(Exception Inner) + : base("None of the specified endpoints were reachable", Inner) + { + } } } diff --git a/projects/RabbitMQ.Client/client/exceptions/ChannelAllocationException.cs b/projects/RabbitMQ.Client/client/exceptions/ChannelAllocationException.cs index ba3a9faa3c..a28acbe59e 100644 --- a/projects/RabbitMQ.Client/client/exceptions/ChannelAllocationException.cs +++ b/projects/RabbitMQ.Client/client/exceptions/ChannelAllocationException.cs @@ -31,36 +31,37 @@ using System; -namespace RabbitMQ.Client.Exceptions; - -/// Thrown when a SessionManager cannot allocate a new -/// channel number, or the requested channel number is already in -/// use. -[Serializable] -public class ChannelAllocationException : ProtocolViolationException +namespace RabbitMQ.Client.Exceptions { - /// - /// Indicates that there are no more free channels. - /// - public ChannelAllocationException() - : base("The connection cannot support any more channels. Consider creating a new connection") + /// Thrown when a SessionManager cannot allocate a new + /// channel number, or the requested channel number is already in + /// use. + [Serializable] + public class ChannelAllocationException : ProtocolViolationException { - Channel = -1; - } + /// + /// Indicates that there are no more free channels. + /// + public ChannelAllocationException() + : base("The connection cannot support any more channels. Consider creating a new connection") + { + Channel = -1; + } - /// - /// Indicates that the specified channel is in use - /// - /// The requested channel number - public ChannelAllocationException(int channel) - : base($"The Requested Channel ({channel}) is already in use.") - { - Channel = channel; - } + /// + /// Indicates that the specified channel is in use + /// + /// The requested channel number + public ChannelAllocationException(int channel) + : base($"The Requested Channel ({channel}) is already in use.") + { + Channel = channel; + } - ///Retrieves the channel number concerned; will - ///return -1 in the case where "no more free channels" is - ///being signaled, or a non-negative integer when "channel is - ///in use" is being signaled. - public int Channel { get; } + ///Retrieves the channel number concerned; will + ///return -1 in the case where "no more free channels" is + ///being signaled, or a non-negative integer when "channel is + ///in use" is being signaled. + public int Channel { get; } + } } diff --git a/projects/RabbitMQ.Client/client/exceptions/ConnectFailureException.cs b/projects/RabbitMQ.Client/client/exceptions/ConnectFailureException.cs index bc1d34a9fc..5d0599617a 100644 --- a/projects/RabbitMQ.Client/client/exceptions/ConnectFailureException.cs +++ b/projects/RabbitMQ.Client/client/exceptions/ConnectFailureException.cs @@ -31,14 +31,15 @@ using System; -namespace RabbitMQ.Client.Exceptions; - -/// Thrown when a connection to the broker fails -[Serializable] -public class ConnectFailureException : ProtocolViolationException +namespace RabbitMQ.Client.Exceptions { - public ConnectFailureException(string msg, Exception inner) - : base(msg, inner) + /// Thrown when a connection to the broker fails + [Serializable] + public class ConnectFailureException : ProtocolViolationException { + public ConnectFailureException(string msg, Exception inner) + : base(msg, inner) + { + } } } diff --git a/projects/RabbitMQ.Client/client/exceptions/HardProtocolException.cs b/projects/RabbitMQ.Client/client/exceptions/HardProtocolException.cs index 96f6c5cfbb..473846f82f 100644 --- a/projects/RabbitMQ.Client/client/exceptions/HardProtocolException.cs +++ b/projects/RabbitMQ.Client/client/exceptions/HardProtocolException.cs @@ -29,13 +29,14 @@ // Copyright (c) 2007-2020 VMware, Inc. All rights reserved. //--------------------------------------------------------------------------- -namespace RabbitMQ.Client.Exceptions; - -///Subclass of ProtocolException representing problems -///requiring a connection.close. -public abstract class HardProtocolException : ProtocolException +namespace RabbitMQ.Client.Exceptions { - protected HardProtocolException(string message) : base(message) + ///Subclass of ProtocolException representing problems + ///requiring a connection.close. + public abstract class HardProtocolException : ProtocolException { + protected HardProtocolException(string message) : base(message) + { + } } } diff --git a/projects/RabbitMQ.Client/client/exceptions/MalformedFrameException.cs b/projects/RabbitMQ.Client/client/exceptions/MalformedFrameException.cs index 1570a17220..3db589a0c5 100644 --- a/projects/RabbitMQ.Client/client/exceptions/MalformedFrameException.cs +++ b/projects/RabbitMQ.Client/client/exceptions/MalformedFrameException.cs @@ -29,23 +29,24 @@ // Copyright (c) 2007-2020 VMware, Inc. All rights reserved. //--------------------------------------------------------------------------- -namespace RabbitMQ.Client.Exceptions; - -///Thrown when frame parsing code detects an error in the -///wire-protocol encoding of a frame. -/// -///For example, potential MalformedFrameException conditions -///include frames too short, frames missing their end marker, and -///invalid protocol negotiation headers. -/// -public class MalformedFrameException : HardProtocolException +namespace RabbitMQ.Client.Exceptions { - public MalformedFrameException(string message) : base(message) + ///Thrown when frame parsing code detects an error in the + ///wire-protocol encoding of a frame. + /// + ///For example, potential MalformedFrameException conditions + ///include frames too short, frames missing their end marker, and + ///invalid protocol negotiation headers. + /// + public class MalformedFrameException : HardProtocolException { - } + public MalformedFrameException(string message) : base(message) + { + } - public override ushort ReplyCode - { - get { return Constants.FrameError; } + public override ushort ReplyCode + { + get { return Constants.FrameError; } + } } } diff --git a/projects/RabbitMQ.Client/client/exceptions/OperationInterruptedException.cs b/projects/RabbitMQ.Client/client/exceptions/OperationInterruptedException.cs index 362fed2eb2..ad739931be 100644 --- a/projects/RabbitMQ.Client/client/exceptions/OperationInterruptedException.cs +++ b/projects/RabbitMQ.Client/client/exceptions/OperationInterruptedException.cs @@ -31,52 +31,53 @@ using System; -namespace RabbitMQ.Client.Exceptions; - -/// -/// Thrown when a session is destroyed during an RPC call to a -/// broker. For example, if a TCP connection dropping causes the -/// destruction of a session in the middle of a QueueDeclare -/// operation, an OperationInterruptedException will be thrown to -/// the caller of IModel.QueueDeclare. -/// -[Serializable] -public class OperationInterruptedException - // TODO: inherit from OperationCanceledException - : RabbitMQClientException +namespace RabbitMQ.Client.Exceptions { - ///Construct an OperationInterruptedException with - ///the passed-in explanation, if any. - public OperationInterruptedException(ShutdownEventArgs reason) - : base(reason is null ? "The AMQP operation was interrupted" : - $"The AMQP operation was interrupted: {reason}") + /// + /// Thrown when a session is destroyed during an RPC call to a + /// broker. For example, if a TCP connection dropping causes the + /// destruction of a session in the middle of a QueueDeclare + /// operation, an OperationInterruptedException will be thrown to + /// the caller of IModel.QueueDeclare. + /// + [Serializable] + public class OperationInterruptedException + // TODO: inherit from OperationCanceledException + : RabbitMQClientException { - ShutdownReason = reason; - } + ///Construct an OperationInterruptedException with + ///the passed-in explanation, if any. + public OperationInterruptedException(ShutdownEventArgs reason) + : base(reason is null ? "The AMQP operation was interrupted" : + $"The AMQP operation was interrupted: {reason}") + { + ShutdownReason = reason; + } - ///Construct an OperationInterruptedException with - ///the passed-in explanation and prefix, if any. - public OperationInterruptedException(ShutdownEventArgs reason, string prefix) - : base(reason is null ? $"{prefix}: The AMQP operation was interrupted" : - $"{prefix}: The AMQP operation was interrupted: {reason}") - { - ShutdownReason = reason; - } + ///Construct an OperationInterruptedException with + ///the passed-in explanation and prefix, if any. + public OperationInterruptedException(ShutdownEventArgs reason, string prefix) + : base(reason is null ? $"{prefix}: The AMQP operation was interrupted" : + $"{prefix}: The AMQP operation was interrupted: {reason}") + { + ShutdownReason = reason; + } - protected OperationInterruptedException() - { - } + protected OperationInterruptedException() + { + } - protected OperationInterruptedException(string message) : base(message) - { - } + protected OperationInterruptedException(string message) : base(message) + { + } - protected OperationInterruptedException(string message, Exception inner) - : base(message, inner) - { - } + protected OperationInterruptedException(string message, Exception inner) + : base(message, inner) + { + } - ///Retrieves the explanation for the shutdown. May - ///return null if no explanation is available. - public ShutdownEventArgs ShutdownReason { get; protected set; } + ///Retrieves the explanation for the shutdown. May + ///return null if no explanation is available. + public ShutdownEventArgs ShutdownReason { get; protected set; } + } } diff --git a/projects/RabbitMQ.Client/client/exceptions/PacketNotRecognizedException.cs b/projects/RabbitMQ.Client/client/exceptions/PacketNotRecognizedException.cs index 6b4a0a8489..487792ee60 100644 --- a/projects/RabbitMQ.Client/client/exceptions/PacketNotRecognizedException.cs +++ b/projects/RabbitMQ.Client/client/exceptions/PacketNotRecognizedException.cs @@ -31,41 +31,42 @@ using System; -namespace RabbitMQ.Client.Exceptions; - -///Thrown to indicate that the peer didn't understand -///the packet received from the client. Peer sent default message -///describing protocol version it is using and transport parameters. -/// -/// -///The peer's {'A','M','Q','P',txHi,txLo,major,minor} packet is -///decoded into instances of this class. -/// -[Serializable] -public class PacketNotRecognizedException : RabbitMQClientException +namespace RabbitMQ.Client.Exceptions { - ///Fills the new instance's properties with the values passed in. - public PacketNotRecognizedException(int transportHigh, - int transportLow, - int serverMajor, - int serverMinor) - : base($"AMQP server protocol version {serverMajor}-{serverMinor}, transport parameters {transportHigh}:{transportLow}") + ///Thrown to indicate that the peer didn't understand + ///the packet received from the client. Peer sent default message + ///describing protocol version it is using and transport parameters. + /// + /// + ///The peer's {'A','M','Q','P',txHi,txLo,major,minor} packet is + ///decoded into instances of this class. + /// + [Serializable] + public class PacketNotRecognizedException : RabbitMQClientException { - TransportHigh = transportHigh; - TransportLow = transportLow; - ServerMajor = serverMajor; - ServerMinor = serverMinor; - } + ///Fills the new instance's properties with the values passed in. + public PacketNotRecognizedException(int transportHigh, + int transportLow, + int serverMajor, + int serverMinor) + : base($"AMQP server protocol version {serverMajor}-{serverMinor}, transport parameters {transportHigh}:{transportLow}") + { + TransportHigh = transportHigh; + TransportLow = transportLow; + ServerMajor = serverMajor; + ServerMinor = serverMinor; + } - ///The peer's AMQP specification major version. - public int ServerMajor { get; } + ///The peer's AMQP specification major version. + public int ServerMajor { get; } - ///The peer's AMQP specification minor version. - public int ServerMinor { get; } + ///The peer's AMQP specification minor version. + public int ServerMinor { get; } - ///The peer's high transport byte. - public int TransportHigh { get; } + ///The peer's high transport byte. + public int TransportHigh { get; } - ///The peer's low transport byte. - public int TransportLow { get; } + ///The peer's low transport byte. + public int TransportLow { get; } + } } diff --git a/projects/RabbitMQ.Client/client/exceptions/PossibleAuthenticationFailureException.cs b/projects/RabbitMQ.Client/client/exceptions/PossibleAuthenticationFailureException.cs index d09882a27d..e6b2ec481b 100644 --- a/projects/RabbitMQ.Client/client/exceptions/PossibleAuthenticationFailureException.cs +++ b/projects/RabbitMQ.Client/client/exceptions/PossibleAuthenticationFailureException.cs @@ -31,17 +31,18 @@ using System; -namespace RabbitMQ.Client.Exceptions; - -/// Thrown when the likely cause is an -/// authentication failure. -[Serializable] -public class PossibleAuthenticationFailureException : RabbitMQClientException +namespace RabbitMQ.Client.Exceptions { - public PossibleAuthenticationFailureException(string msg, Exception inner) : base(msg, inner) - { - } - public PossibleAuthenticationFailureException(string msg) : base(msg) + /// Thrown when the likely cause is an + /// authentication failure. + [Serializable] + public class PossibleAuthenticationFailureException : RabbitMQClientException { + public PossibleAuthenticationFailureException(string msg, Exception inner) : base(msg, inner) + { + } + public PossibleAuthenticationFailureException(string msg) : base(msg) + { + } } } diff --git a/projects/RabbitMQ.Client/client/exceptions/ProtocolException.cs b/projects/RabbitMQ.Client/client/exceptions/ProtocolException.cs index 6bc00c4e6a..f24d297029 100644 --- a/projects/RabbitMQ.Client/client/exceptions/ProtocolException.cs +++ b/projects/RabbitMQ.Client/client/exceptions/ProtocolException.cs @@ -29,29 +29,30 @@ // Copyright (c) 2007-2020 VMware, Inc. All rights reserved. //--------------------------------------------------------------------------- -namespace RabbitMQ.Client.Exceptions; - -/// Instances of subclasses of subclasses -/// HardProtocolException and SoftProtocolException are thrown in -/// situations when we detect a problem with the connection-, -/// channel- or wire-level parts of the AMQP protocol. -public abstract class ProtocolException : RabbitMQClientException +namespace RabbitMQ.Client.Exceptions { - protected ProtocolException(string message) : base(message) + /// Instances of subclasses of subclasses + /// HardProtocolException and SoftProtocolException are thrown in + /// situations when we detect a problem with the connection-, + /// channel- or wire-level parts of the AMQP protocol. + public abstract class ProtocolException : RabbitMQClientException { - } + protected ProtocolException(string message) : base(message) + { + } - ///Retrieve the reply code to use in a - ///connection/channel close method. - public abstract ushort ReplyCode { get; } + ///Retrieve the reply code to use in a + ///connection/channel close method. + public abstract ushort ReplyCode { get; } - ///Retrieve the shutdown details to use in a - ///connection/channel close method. Defaults to using - ///ShutdownInitiator.Library, and this.ReplyCode and - ///this.Message as the reply code and text, - ///respectively. - public virtual ShutdownEventArgs ShutdownReason - { - get { return new ShutdownEventArgs(ShutdownInitiator.Library, ReplyCode, Message, this); } + ///Retrieve the shutdown details to use in a + ///connection/channel close method. Defaults to using + ///ShutdownInitiator.Library, and this.ReplyCode and + ///this.Message as the reply code and text, + ///respectively. + public virtual ShutdownEventArgs ShutdownReason + { + get { return new ShutdownEventArgs(ShutdownInitiator.Library, ReplyCode, Message, this); } + } } } diff --git a/projects/RabbitMQ.Client/client/exceptions/ProtocolVersionMismatchException.cs b/projects/RabbitMQ.Client/client/exceptions/ProtocolVersionMismatchException.cs index eb54313141..dc430a0660 100644 --- a/projects/RabbitMQ.Client/client/exceptions/ProtocolVersionMismatchException.cs +++ b/projects/RabbitMQ.Client/client/exceptions/ProtocolVersionMismatchException.cs @@ -31,41 +31,42 @@ using System; -namespace RabbitMQ.Client.Exceptions; - -///Thrown to indicate that the peer does not support the -///wire protocol version we requested immediately after opening -///the TCP socket. -[Serializable] -public class ProtocolVersionMismatchException : ProtocolViolationException +namespace RabbitMQ.Client.Exceptions { - ///Fills the new instance's properties with the values passed in. - public ProtocolVersionMismatchException(int clientMajor, - int clientMinor, - int serverMajor, - int serverMinor) - : base($"AMQP server protocol negotiation failure: server version {positiveOrUnknown(serverMajor)}-{positiveOrUnknown(serverMinor)}, client version {positiveOrUnknown(clientMajor)}-{positiveOrUnknown(clientMinor)}") + ///Thrown to indicate that the peer does not support the + ///wire protocol version we requested immediately after opening + ///the TCP socket. + [Serializable] + public class ProtocolVersionMismatchException : ProtocolViolationException { - ClientMajor = clientMajor; - ClientMinor = clientMinor; - ServerMajor = serverMajor; - ServerMinor = serverMinor; - } + ///Fills the new instance's properties with the values passed in. + public ProtocolVersionMismatchException(int clientMajor, + int clientMinor, + int serverMajor, + int serverMinor) + : base($"AMQP server protocol negotiation failure: server version {positiveOrUnknown(serverMajor)}-{positiveOrUnknown(serverMinor)}, client version {positiveOrUnknown(clientMajor)}-{positiveOrUnknown(clientMinor)}") + { + ClientMajor = clientMajor; + ClientMinor = clientMinor; + ServerMajor = serverMajor; + ServerMinor = serverMinor; + } - ///The client's AMQP specification major version. - public int ClientMajor { get; } + ///The client's AMQP specification major version. + public int ClientMajor { get; } - ///The client's AMQP specification minor version. - public int ClientMinor { get; } + ///The client's AMQP specification minor version. + public int ClientMinor { get; } - ///The peer's AMQP specification major version. - public int ServerMajor { get; } + ///The peer's AMQP specification major version. + public int ServerMajor { get; } - ///The peer's AMQP specification minor version. - public int ServerMinor { get; } + ///The peer's AMQP specification minor version. + public int ServerMinor { get; } - private static string positiveOrUnknown(int version) - { - return version >= 0 ? version.ToString() : "unknown"; + private static string positiveOrUnknown(int version) + { + return version >= 0 ? version.ToString() : "unknown"; + } } } diff --git a/projects/RabbitMQ.Client/client/exceptions/ProtocolViolationException.cs b/projects/RabbitMQ.Client/client/exceptions/ProtocolViolationException.cs index 91ee2d15e9..b5bc9826ec 100644 --- a/projects/RabbitMQ.Client/client/exceptions/ProtocolViolationException.cs +++ b/projects/RabbitMQ.Client/client/exceptions/ProtocolViolationException.cs @@ -31,18 +31,19 @@ using System; -namespace RabbitMQ.Client.Exceptions; - -[Serializable] -public class ProtocolViolationException : RabbitMQClientException +namespace RabbitMQ.Client.Exceptions { - public ProtocolViolationException(string message) : base(message) - { - } - public ProtocolViolationException(string message, Exception inner) : base(message, inner) - { - } - public ProtocolViolationException() + [Serializable] + public class ProtocolViolationException : RabbitMQClientException { + public ProtocolViolationException(string message) : base(message) + { + } + public ProtocolViolationException(string message, Exception inner) : base(message, inner) + { + } + public ProtocolViolationException() + { + } } } diff --git a/projects/RabbitMQ.Client/client/exceptions/RabbitMQClientException.cs b/projects/RabbitMQ.Client/client/exceptions/RabbitMQClientException.cs index c9282e0e40..99f1a3a7b3 100644 --- a/projects/RabbitMQ.Client/client/exceptions/RabbitMQClientException.cs +++ b/projects/RabbitMQ.Client/client/exceptions/RabbitMQClientException.cs @@ -31,29 +31,30 @@ using System; -namespace RabbitMQ.Client.Exceptions; - -[Serializable] -public abstract class RabbitMQClientException : Exception +namespace RabbitMQ.Client.Exceptions { - /// Initializes a new instance of the class. - protected RabbitMQClientException() + [Serializable] + public abstract class RabbitMQClientException : Exception { + /// Initializes a new instance of the class. + protected RabbitMQClientException() + { - } + } - /// Initializes a new instance of the class with a specified error message. - /// The message that describes the error. - protected RabbitMQClientException(string message) : base(message) - { + /// Initializes a new instance of the class with a specified error message. + /// The message that describes the error. + protected RabbitMQClientException(string message) : base(message) + { - } + } - /// Initializes a new instance of the class with a specified error message and a reference to the inner exception that is the cause of this exception. - /// The error message that explains the reason for the exception. - /// The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) if no inner exception is specified. - protected RabbitMQClientException(string message, Exception innerException) : base(message, innerException) - { + /// Initializes a new instance of the class with a specified error message and a reference to the inner exception that is the cause of this exception. + /// The error message that explains the reason for the exception. + /// The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) if no inner exception is specified. + protected RabbitMQClientException(string message, Exception innerException) : base(message, innerException) + { + } } } diff --git a/projects/RabbitMQ.Client/client/exceptions/SyntaxErrorException.cs b/projects/RabbitMQ.Client/client/exceptions/SyntaxErrorException.cs index d5d463dd06..61f3688dd9 100644 --- a/projects/RabbitMQ.Client/client/exceptions/SyntaxErrorException.cs +++ b/projects/RabbitMQ.Client/client/exceptions/SyntaxErrorException.cs @@ -29,18 +29,19 @@ // Copyright (c) 2007-2020 VMware, Inc. All rights reserved. //--------------------------------------------------------------------------- -namespace RabbitMQ.Client.Exceptions; - -/// Thrown when our peer sends a frame that contains -/// illegal values for one or more fields. -public class SyntaxErrorException : HardProtocolException +namespace RabbitMQ.Client.Exceptions { - public SyntaxErrorException(string message) : base(message) + /// Thrown when our peer sends a frame that contains + /// illegal values for one or more fields. + public class SyntaxErrorException : HardProtocolException { - } + public SyntaxErrorException(string message) : base(message) + { + } - public override ushort ReplyCode - { - get { return Constants.SyntaxError; } + public override ushort ReplyCode + { + get { return Constants.SyntaxError; } + } } } diff --git a/projects/RabbitMQ.Client/client/exceptions/TopologyRecoveryException.cs b/projects/RabbitMQ.Client/client/exceptions/TopologyRecoveryException.cs index 5f752ca996..0c494c7213 100644 --- a/projects/RabbitMQ.Client/client/exceptions/TopologyRecoveryException.cs +++ b/projects/RabbitMQ.Client/client/exceptions/TopologyRecoveryException.cs @@ -31,11 +31,12 @@ using System; -namespace RabbitMQ.Client.Exceptions; - -public class TopologyRecoveryException : RabbitMQClientException +namespace RabbitMQ.Client.Exceptions { - public TopologyRecoveryException(string message, Exception cause) : base(message, cause) + public class TopologyRecoveryException : RabbitMQClientException { + public TopologyRecoveryException(string message, Exception cause) : base(message, cause) + { + } } } diff --git a/projects/RabbitMQ.Client/client/exceptions/UnexpectedFrameException.cs b/projects/RabbitMQ.Client/client/exceptions/UnexpectedFrameException.cs index 7b4c1325a2..e04f874429 100644 --- a/projects/RabbitMQ.Client/client/exceptions/UnexpectedFrameException.cs +++ b/projects/RabbitMQ.Client/client/exceptions/UnexpectedFrameException.cs @@ -31,19 +31,20 @@ using RabbitMQ.Client.Impl; -namespace RabbitMQ.Client.Exceptions; - -/// -/// Thrown when the connection receives a frame that it wasn't expecting. -/// -public class UnexpectedFrameException : HardProtocolException +namespace RabbitMQ.Client.Exceptions { - internal UnexpectedFrameException(FrameType frameType) : base($"A frame of type {frameType} was not expected at this time") + /// + /// Thrown when the connection receives a frame that it wasn't expecting. + /// + public class UnexpectedFrameException : HardProtocolException { - } + internal UnexpectedFrameException(FrameType frameType) : base($"A frame of type {frameType} was not expected at this time") + { + } - public override ushort ReplyCode - { - get { return Constants.CommandInvalid; } + public override ushort ReplyCode + { + get { return Constants.CommandInvalid; } + } } } diff --git a/projects/RabbitMQ.Client/client/exceptions/UnexpectedMethodException.cs b/projects/RabbitMQ.Client/client/exceptions/UnexpectedMethodException.cs index dc8a0bfaeb..84c519d33a 100644 --- a/projects/RabbitMQ.Client/client/exceptions/UnexpectedMethodException.cs +++ b/projects/RabbitMQ.Client/client/exceptions/UnexpectedMethodException.cs @@ -32,50 +32,51 @@ using System; using RabbitMQ.Client.client.framing; -namespace RabbitMQ.Client.Exceptions; - -/// -/// Thrown when the model receives an RPC reply that it wasn't expecting. -/// -[Serializable] -public class UnexpectedMethodException : ProtocolViolationException +namespace RabbitMQ.Client.Exceptions { - private readonly ProtocolCommandId _receivedCommandId; - private readonly ProtocolCommandId _expectedCommandId; - - internal UnexpectedMethodException(ProtocolCommandId receivedCommandId, ProtocolCommandId expectedCommandId) - { - _receivedCommandId = receivedCommandId; - _expectedCommandId = expectedCommandId; - } - /// - /// Retrieves the class ID number of this method, as defined in the AMQP specification XML. + /// Thrown when the model receives an RPC reply that it wasn't expecting. /// - public ushort ProtocolClassId => (ushort)((uint)_receivedCommandId >> 16); + [Serializable] + public class UnexpectedMethodException : ProtocolViolationException + { + private readonly ProtocolCommandId _receivedCommandId; + private readonly ProtocolCommandId _expectedCommandId; - /// - /// Retrieves the method ID number of this method, as defined in the AMQP specification XML. - /// - public ushort ProtocolMethodId => (ushort)((uint)_receivedCommandId & 0xFFFF); + internal UnexpectedMethodException(ProtocolCommandId receivedCommandId, ProtocolCommandId expectedCommandId) + { + _receivedCommandId = receivedCommandId; + _expectedCommandId = expectedCommandId; + } - /// - /// Retrieves the name of this method - for debugging use. - /// - public string ProtocolMethodName => _receivedCommandId.ToString(); + /// + /// Retrieves the class ID number of this method, as defined in the AMQP specification XML. + /// + public ushort ProtocolClassId => (ushort)((uint)_receivedCommandId >> 16); - /// - /// Retrieves the expected class ID number of this method, as defined in the AMQP specification XML. - /// - public ushort ExpectedProtocolClassId => (ushort)((uint)_expectedCommandId >> 16); + /// + /// Retrieves the method ID number of this method, as defined in the AMQP specification XML. + /// + public ushort ProtocolMethodId => (ushort)((uint)_receivedCommandId & 0xFFFF); - /// - /// Retrieves the expected method ID number of this method, as defined in the AMQP specification XML. - /// - public ushort ExpectedProtocolMethodId => (ushort)((uint)_expectedCommandId & 0xFFFF); + /// + /// Retrieves the name of this method - for debugging use. + /// + public string ProtocolMethodName => _receivedCommandId.ToString(); - /// - /// Retrieves the expected name of this method - for debugging use. - /// - public string ExpectedProtocolMethodName => _expectedCommandId.ToString(); + /// + /// Retrieves the expected class ID number of this method, as defined in the AMQP specification XML. + /// + public ushort ExpectedProtocolClassId => (ushort)((uint)_expectedCommandId >> 16); + + /// + /// Retrieves the expected method ID number of this method, as defined in the AMQP specification XML. + /// + public ushort ExpectedProtocolMethodId => (ushort)((uint)_expectedCommandId & 0xFFFF); + + /// + /// Retrieves the expected name of this method - for debugging use. + /// + public string ExpectedProtocolMethodName => _expectedCommandId.ToString(); + } } diff --git a/projects/RabbitMQ.Client/client/exceptions/UnknownClassOrMethodException.cs b/projects/RabbitMQ.Client/client/exceptions/UnknownClassOrMethodException.cs index b8cd86b819..999d71c6a8 100644 --- a/projects/RabbitMQ.Client/client/exceptions/UnknownClassOrMethodException.cs +++ b/projects/RabbitMQ.Client/client/exceptions/UnknownClassOrMethodException.cs @@ -29,36 +29,37 @@ // Copyright (c) 2007-2020 VMware, Inc. All rights reserved. //--------------------------------------------------------------------------- -namespace RabbitMQ.Client.Exceptions; - -/// -/// Thrown when the protocol handlers detect an unknown class -/// number or method number. -/// -public class UnknownClassOrMethodException : HardProtocolException +namespace RabbitMQ.Client.Exceptions { - public UnknownClassOrMethodException(ushort classId, ushort methodId) - : base($"The Class or Method <{classId}.{methodId}> is unknown") + /// + /// Thrown when the protocol handlers detect an unknown class + /// number or method number. + /// + public class UnknownClassOrMethodException : HardProtocolException { - ClassId = classId; - MethodId = methodId; - } + public UnknownClassOrMethodException(ushort classId, ushort methodId) + : base($"The Class or Method <{classId}.{methodId}> is unknown") + { + ClassId = classId; + MethodId = methodId; + } - ///The AMQP content-class ID. - public ushort ClassId { get; } + ///The AMQP content-class ID. + public ushort ClassId { get; } - ///The AMQP method ID within the content-class, or 0 if none. - public ushort MethodId { get; } + ///The AMQP method ID within the content-class, or 0 if none. + public ushort MethodId { get; } - public override ushort ReplyCode - { - get { return Constants.NotImplemented; } - } + public override ushort ReplyCode + { + get { return Constants.NotImplemented; } + } - public override string ToString() - { - return MethodId == 0 - ? $"{base.ToString()}<{ClassId}>" - : $"{base.ToString()}<{ClassId}.{MethodId}>"; + public override string ToString() + { + return MethodId == 0 + ? $"{base.ToString()}<{ClassId}>" + : $"{base.ToString()}<{ClassId}.{MethodId}>"; + } } } diff --git a/projects/RabbitMQ.Client/client/exceptions/WireFormattingException.cs b/projects/RabbitMQ.Client/client/exceptions/WireFormattingException.cs index c548348a32..3d879f19ec 100644 --- a/projects/RabbitMQ.Client/client/exceptions/WireFormattingException.cs +++ b/projects/RabbitMQ.Client/client/exceptions/WireFormattingException.cs @@ -31,28 +31,29 @@ using System; -namespace RabbitMQ.Client.Exceptions; - -/// Thrown when the wire-formatting code cannot encode a -/// particular .NET value to AMQP protocol format. -[Serializable] -public class WireFormattingException : ProtocolViolationException +namespace RabbitMQ.Client.Exceptions { - ///Construct a WireFormattingException with no - ///particular offender (i.e. null) - public WireFormattingException(string message) : this(message, null) + /// Thrown when the wire-formatting code cannot encode a + /// particular .NET value to AMQP protocol format. + [Serializable] + public class WireFormattingException : ProtocolViolationException { - } + ///Construct a WireFormattingException with no + ///particular offender (i.e. null) + public WireFormattingException(string message) : this(message, null) + { + } - ///Construct a WireFormattingException with the given - ///offender - public WireFormattingException(string message, object offender) - : base(message) - { - Offender = offender; - } + ///Construct a WireFormattingException with the given + ///offender + public WireFormattingException(string message, object offender) + : base(message) + { + Offender = offender; + } - ///Object which this exception is complaining about; - ///may be null if no particular offender exists - public object Offender { get; } + ///Object which this exception is complaining about; + ///may be null if no particular offender exists + public object Offender { get; } + } } diff --git a/projects/RabbitMQ.Client/client/framing/BasicAck.cs b/projects/RabbitMQ.Client/client/framing/BasicAck.cs index 6601255e72..027257e525 100644 --- a/projects/RabbitMQ.Client/client/framing/BasicAck.cs +++ b/projects/RabbitMQ.Client/client/framing/BasicAck.cs @@ -35,36 +35,37 @@ using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Impl; -namespace RabbitMQ.Client.Framing.Impl; - -internal readonly struct BasicAck : IOutgoingAmqpMethod +namespace RabbitMQ.Client.Framing.Impl { - public readonly ulong _deliveryTag; - public readonly bool _multiple; - - public BasicAck(ulong DeliveryTag, bool Multiple) + internal readonly struct BasicAck : IOutgoingAmqpMethod { - _deliveryTag = DeliveryTag; - _multiple = Multiple; - } + public readonly ulong _deliveryTag; + public readonly bool _multiple; - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public BasicAck(ReadOnlySpan span) - { - int offset = WireFormatting.ReadLonglong(span, out _deliveryTag); - WireFormatting.ReadBits(span.Slice(offset), out _multiple); - } + public BasicAck(ulong DeliveryTag, bool Multiple) + { + _deliveryTag = DeliveryTag; + _multiple = Multiple; + } - public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.BasicAck; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public BasicAck(ReadOnlySpan span) + { + int offset = WireFormatting.ReadLonglong(span, out _deliveryTag); + WireFormatting.ReadBits(span.Slice(offset), out _multiple); + } - public int WriteTo(Span span) - { - int offset = WireFormatting.WriteLonglong(ref span.GetStart(), _deliveryTag); - return offset + WireFormatting.WriteBits(ref span.GetOffset(offset), _multiple); - } + public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.BasicAck; - public int GetRequiredBufferSize() - { - return 8 + 1; + public int WriteTo(Span span) + { + int offset = WireFormatting.WriteLonglong(ref span.GetStart(), _deliveryTag); + return offset + WireFormatting.WriteBits(ref span.GetOffset(offset), _multiple); + } + + public int GetRequiredBufferSize() + { + return 8 + 1; + } } } diff --git a/projects/RabbitMQ.Client/client/framing/BasicCancel.cs b/projects/RabbitMQ.Client/client/framing/BasicCancel.cs index 367e0787ff..bec131c4e7 100644 --- a/projects/RabbitMQ.Client/client/framing/BasicCancel.cs +++ b/projects/RabbitMQ.Client/client/framing/BasicCancel.cs @@ -34,37 +34,38 @@ using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Impl; -namespace RabbitMQ.Client.Framing.Impl; - -internal readonly struct BasicCancel : IOutgoingAmqpMethod +namespace RabbitMQ.Client.Framing.Impl { - public readonly string _consumerTag; - public readonly bool _nowait; - - public BasicCancel(string ConsumerTag, bool Nowait) + internal readonly struct BasicCancel : IOutgoingAmqpMethod { - _consumerTag = ConsumerTag; - _nowait = Nowait; - } + public readonly string _consumerTag; + public readonly bool _nowait; - public BasicCancel(ReadOnlySpan span) - { - int offset = WireFormatting.ReadShortstr(span, out _consumerTag); - WireFormatting.ReadBits(span.Slice(offset), out _nowait); - } + public BasicCancel(string ConsumerTag, bool Nowait) + { + _consumerTag = ConsumerTag; + _nowait = Nowait; + } - public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.BasicCancel; + public BasicCancel(ReadOnlySpan span) + { + int offset = WireFormatting.ReadShortstr(span, out _consumerTag); + WireFormatting.ReadBits(span.Slice(offset), out _nowait); + } - public int WriteTo(Span span) - { - int offset = WireFormatting.WriteShortstr(ref span.GetStart(), _consumerTag); - return offset + WireFormatting.WriteBits(ref span.GetOffset(offset), _nowait); - } + public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.BasicCancel; - public int GetRequiredBufferSize() - { - int bufferSize = 1 + 1; // bytes for length of _consumerTag, bit fields - bufferSize += WireFormatting.GetByteCount(_consumerTag); // _consumerTag in bytes - return bufferSize; + public int WriteTo(Span span) + { + int offset = WireFormatting.WriteShortstr(ref span.GetStart(), _consumerTag); + return offset + WireFormatting.WriteBits(ref span.GetOffset(offset), _nowait); + } + + public int GetRequiredBufferSize() + { + int bufferSize = 1 + 1; // bytes for length of _consumerTag, bit fields + bufferSize += WireFormatting.GetByteCount(_consumerTag); // _consumerTag in bytes + return bufferSize; + } } } diff --git a/projects/RabbitMQ.Client/client/framing/BasicCancelOk.cs b/projects/RabbitMQ.Client/client/framing/BasicCancelOk.cs index 6557947835..a6fa8df152 100644 --- a/projects/RabbitMQ.Client/client/framing/BasicCancelOk.cs +++ b/projects/RabbitMQ.Client/client/framing/BasicCancelOk.cs @@ -34,16 +34,17 @@ using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Impl; -namespace RabbitMQ.Client.Framing.Impl; - -internal readonly struct BasicCancelOk : IAmqpMethod +namespace RabbitMQ.Client.Framing.Impl { - public readonly string _consumerTag; - - public BasicCancelOk(ReadOnlySpan span) + internal readonly struct BasicCancelOk : IAmqpMethod { - WireFormatting.ReadShortstr(span, out _consumerTag); - } + public readonly string _consumerTag; - public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.BasicCancelOk; + public BasicCancelOk(ReadOnlySpan span) + { + WireFormatting.ReadShortstr(span, out _consumerTag); + } + + public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.BasicCancelOk; + } } diff --git a/projects/RabbitMQ.Client/client/framing/BasicConsume.cs b/projects/RabbitMQ.Client/client/framing/BasicConsume.cs index 2ff0a8cf45..05e0234704 100644 --- a/projects/RabbitMQ.Client/client/framing/BasicConsume.cs +++ b/projects/RabbitMQ.Client/client/framing/BasicConsume.cs @@ -35,48 +35,49 @@ using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Impl; -namespace RabbitMQ.Client.Framing.Impl; - -internal readonly struct BasicConsume : IOutgoingAmqpMethod +namespace RabbitMQ.Client.Framing.Impl { - // deprecated - // ushort _reserved1 - public readonly string _queue; - public readonly string _consumerTag; - public readonly bool _noLocal; - public readonly bool _noAck; - public readonly bool _exclusive; - public readonly bool _nowait; - public readonly IDictionary _arguments; - - public BasicConsume(string Queue, string ConsumerTag, bool NoLocal, bool NoAck, bool Exclusive, bool Nowait, IDictionary Arguments) + internal readonly struct BasicConsume : IOutgoingAmqpMethod { - _queue = Queue; - _consumerTag = ConsumerTag; - _noLocal = NoLocal; - _noAck = NoAck; - _exclusive = Exclusive; - _nowait = Nowait; - _arguments = Arguments; - } + // deprecated + // ushort _reserved1 + public readonly string _queue; + public readonly string _consumerTag; + public readonly bool _noLocal; + public readonly bool _noAck; + public readonly bool _exclusive; + public readonly bool _nowait; + public readonly IDictionary _arguments; - public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.BasicConsume; + public BasicConsume(string Queue, string ConsumerTag, bool NoLocal, bool NoAck, bool Exclusive, bool Nowait, IDictionary Arguments) + { + _queue = Queue; + _consumerTag = ConsumerTag; + _noLocal = NoLocal; + _noAck = NoAck; + _exclusive = Exclusive; + _nowait = Nowait; + _arguments = Arguments; + } - public int WriteTo(Span span) - { - int offset = WireFormatting.WriteShort(ref span.GetStart(), default); - offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _queue); - offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _consumerTag); - offset += WireFormatting.WriteBits(ref span.GetOffset(offset), _noLocal, _noAck, _exclusive, _nowait); - return offset + WireFormatting.WriteTable(ref span.GetOffset(offset), _arguments); - } + public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.BasicConsume; - public int GetRequiredBufferSize() - { - int bufferSize = 2 + 1 + 1 + 1; // bytes for _reserved1, length of _queue, length of _consumerTag, bit fields - bufferSize += WireFormatting.GetByteCount(_queue); // _queue in bytes - bufferSize += WireFormatting.GetByteCount(_consumerTag); // _consumerTag in bytes - bufferSize += WireFormatting.GetTableByteCount(_arguments); // _arguments in bytes - return bufferSize; + public int WriteTo(Span span) + { + int offset = WireFormatting.WriteShort(ref span.GetStart(), default); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _queue); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _consumerTag); + offset += WireFormatting.WriteBits(ref span.GetOffset(offset), _noLocal, _noAck, _exclusive, _nowait); + return offset + WireFormatting.WriteTable(ref span.GetOffset(offset), _arguments); + } + + public int GetRequiredBufferSize() + { + int bufferSize = 2 + 1 + 1 + 1; // bytes for _reserved1, length of _queue, length of _consumerTag, bit fields + bufferSize += WireFormatting.GetByteCount(_queue); // _queue in bytes + bufferSize += WireFormatting.GetByteCount(_consumerTag); // _consumerTag in bytes + bufferSize += WireFormatting.GetTableByteCount(_arguments); // _arguments in bytes + return bufferSize; + } } } diff --git a/projects/RabbitMQ.Client/client/framing/BasicConsumeOk.cs b/projects/RabbitMQ.Client/client/framing/BasicConsumeOk.cs index 65473ea07c..c8e325adec 100644 --- a/projects/RabbitMQ.Client/client/framing/BasicConsumeOk.cs +++ b/projects/RabbitMQ.Client/client/framing/BasicConsumeOk.cs @@ -34,16 +34,17 @@ using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Impl; -namespace RabbitMQ.Client.Framing.Impl; - -internal readonly struct BasicConsumeOk : IAmqpMethod +namespace RabbitMQ.Client.Framing.Impl { - public readonly string _consumerTag; - - public BasicConsumeOk(ReadOnlySpan span) + internal readonly struct BasicConsumeOk : IAmqpMethod { - WireFormatting.ReadShortstr(span, out _consumerTag); - } + public readonly string _consumerTag; - public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.BasicConsumeOk; + public BasicConsumeOk(ReadOnlySpan span) + { + WireFormatting.ReadShortstr(span, out _consumerTag); + } + + public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.BasicConsumeOk; + } } diff --git a/projects/RabbitMQ.Client/client/framing/BasicDeliver.cs b/projects/RabbitMQ.Client/client/framing/BasicDeliver.cs index 5a565492e3..ebc49cd4da 100644 --- a/projects/RabbitMQ.Client/client/framing/BasicDeliver.cs +++ b/projects/RabbitMQ.Client/client/framing/BasicDeliver.cs @@ -34,24 +34,25 @@ using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Impl; -namespace RabbitMQ.Client.Framing.Impl; - -internal readonly struct BasicDeliver : IAmqpMethod +namespace RabbitMQ.Client.Framing.Impl { - public readonly string _consumerTag; - public readonly ulong _deliveryTag; - public readonly bool _redelivered; - public readonly string _exchange; - public readonly string _routingKey; - - public BasicDeliver(ReadOnlySpan span) + internal readonly struct BasicDeliver : IAmqpMethod { - int offset = WireFormatting.ReadShortstr(span, out _consumerTag); - offset += WireFormatting.ReadLonglong(span.Slice(offset), out _deliveryTag); - offset += WireFormatting.ReadBits(span.Slice(offset), out _redelivered); - offset += WireFormatting.ReadShortstr(span.Slice(offset), out _exchange); - WireFormatting.ReadShortstr(span.Slice(offset), out _routingKey); - } + public readonly string _consumerTag; + public readonly ulong _deliveryTag; + public readonly bool _redelivered; + public readonly string _exchange; + public readonly string _routingKey; - public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.BasicDeliver; + public BasicDeliver(ReadOnlySpan span) + { + int offset = WireFormatting.ReadShortstr(span, out _consumerTag); + offset += WireFormatting.ReadLonglong(span.Slice(offset), out _deliveryTag); + offset += WireFormatting.ReadBits(span.Slice(offset), out _redelivered); + offset += WireFormatting.ReadShortstr(span.Slice(offset), out _exchange); + WireFormatting.ReadShortstr(span.Slice(offset), out _routingKey); + } + + public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.BasicDeliver; + } } diff --git a/projects/RabbitMQ.Client/client/framing/BasicGet.cs b/projects/RabbitMQ.Client/client/framing/BasicGet.cs index ed7d80b4f9..52e7cf2088 100644 --- a/projects/RabbitMQ.Client/client/framing/BasicGet.cs +++ b/projects/RabbitMQ.Client/client/framing/BasicGet.cs @@ -34,34 +34,35 @@ using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Impl; -namespace RabbitMQ.Client.Framing.Impl; - -internal readonly struct BasicGet : IOutgoingAmqpMethod +namespace RabbitMQ.Client.Framing.Impl { - // deprecated - // ushort _reserved1 - public readonly string _queue; - public readonly bool _noAck; - - public BasicGet(string Queue, bool NoAck) + internal readonly struct BasicGet : IOutgoingAmqpMethod { - _queue = Queue; - _noAck = NoAck; - } + // deprecated + // ushort _reserved1 + public readonly string _queue; + public readonly bool _noAck; - public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.BasicGet; + public BasicGet(string Queue, bool NoAck) + { + _queue = Queue; + _noAck = NoAck; + } - public int WriteTo(Span span) - { - int offset = WireFormatting.WriteShort(ref span.GetStart(), default); - offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _queue); - return offset + WireFormatting.WriteBits(ref span.GetOffset(offset), _noAck); - } + public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.BasicGet; - public int GetRequiredBufferSize() - { - int bufferSize = 2 + 1 + 1; // bytes for _reserved1, length of _queue, bit fields - bufferSize += WireFormatting.GetByteCount(_queue); // _queue in bytes - return bufferSize; + public int WriteTo(Span span) + { + int offset = WireFormatting.WriteShort(ref span.GetStart(), default); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _queue); + return offset + WireFormatting.WriteBits(ref span.GetOffset(offset), _noAck); + } + + public int GetRequiredBufferSize() + { + int bufferSize = 2 + 1 + 1; // bytes for _reserved1, length of _queue, bit fields + bufferSize += WireFormatting.GetByteCount(_queue); // _queue in bytes + return bufferSize; + } } } diff --git a/projects/RabbitMQ.Client/client/framing/BasicGetOk.cs b/projects/RabbitMQ.Client/client/framing/BasicGetOk.cs index 1f31ad61ec..3885727956 100644 --- a/projects/RabbitMQ.Client/client/framing/BasicGetOk.cs +++ b/projects/RabbitMQ.Client/client/framing/BasicGetOk.cs @@ -34,24 +34,25 @@ using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Impl; -namespace RabbitMQ.Client.Framing.Impl; - -internal readonly struct BasicGetOk : IAmqpMethod +namespace RabbitMQ.Client.Framing.Impl { - public readonly ulong _deliveryTag; - public readonly bool _redelivered; - public readonly string _exchange; - public readonly string _routingKey; - public readonly uint _messageCount; - - public BasicGetOk(ReadOnlySpan span) + internal readonly struct BasicGetOk : IAmqpMethod { - int offset = WireFormatting.ReadLonglong(span, out _deliveryTag); - offset += WireFormatting.ReadBits(span.Slice(offset), out _redelivered); - offset += WireFormatting.ReadShortstr(span.Slice(offset), out _exchange); - offset += WireFormatting.ReadShortstr(span.Slice(offset), out _routingKey); - WireFormatting.ReadLong(span.Slice(offset), out _messageCount); - } + public readonly ulong _deliveryTag; + public readonly bool _redelivered; + public readonly string _exchange; + public readonly string _routingKey; + public readonly uint _messageCount; - public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.BasicGetOk; + public BasicGetOk(ReadOnlySpan span) + { + int offset = WireFormatting.ReadLonglong(span, out _deliveryTag); + offset += WireFormatting.ReadBits(span.Slice(offset), out _redelivered); + offset += WireFormatting.ReadShortstr(span.Slice(offset), out _exchange); + offset += WireFormatting.ReadShortstr(span.Slice(offset), out _routingKey); + WireFormatting.ReadLong(span.Slice(offset), out _messageCount); + } + + public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.BasicGetOk; + } } diff --git a/projects/RabbitMQ.Client/client/framing/BasicMethodConstants.cs b/projects/RabbitMQ.Client/client/framing/BasicMethodConstants.cs index a0a3d9631c..32008fc9b1 100644 --- a/projects/RabbitMQ.Client/client/framing/BasicMethodConstants.cs +++ b/projects/RabbitMQ.Client/client/framing/BasicMethodConstants.cs @@ -29,26 +29,27 @@ // Copyright (c) 2007-2020 VMware, Inc. All rights reserved. //--------------------------------------------------------------------------- -namespace RabbitMQ.Client.Framing.Impl; - -internal static class BasicMethodConstants +namespace RabbitMQ.Client.Framing.Impl { - internal const ushort Qos = 10; - internal const ushort QosOk = 11; - internal const ushort Consume = 20; - internal const ushort ConsumeOk = 21; - internal const ushort Cancel = 30; - internal const ushort CancelOk = 31; - internal const ushort Publish = 40; - internal const ushort Return = 50; - internal const ushort Deliver = 60; - internal const ushort Get = 70; - internal const ushort GetOk = 71; - internal const ushort GetEmpty = 72; - internal const ushort Ack = 80; - internal const ushort Reject = 90; - internal const ushort RecoverAsync = 100; - internal const ushort Recover = 110; - internal const ushort RecoverOk = 111; - internal const ushort Nack = 120; + internal static class BasicMethodConstants + { + internal const ushort Qos = 10; + internal const ushort QosOk = 11; + internal const ushort Consume = 20; + internal const ushort ConsumeOk = 21; + internal const ushort Cancel = 30; + internal const ushort CancelOk = 31; + internal const ushort Publish = 40; + internal const ushort Return = 50; + internal const ushort Deliver = 60; + internal const ushort Get = 70; + internal const ushort GetOk = 71; + internal const ushort GetEmpty = 72; + internal const ushort Ack = 80; + internal const ushort Reject = 90; + internal const ushort RecoverAsync = 100; + internal const ushort Recover = 110; + internal const ushort RecoverOk = 111; + internal const ushort Nack = 120; + } } diff --git a/projects/RabbitMQ.Client/client/framing/BasicNack.cs b/projects/RabbitMQ.Client/client/framing/BasicNack.cs index 4674f1e874..6f8a54aa5b 100644 --- a/projects/RabbitMQ.Client/client/framing/BasicNack.cs +++ b/projects/RabbitMQ.Client/client/framing/BasicNack.cs @@ -33,37 +33,38 @@ using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Impl; -namespace RabbitMQ.Client.Framing.Impl; - -internal readonly struct BasicNack : IOutgoingAmqpMethod +namespace RabbitMQ.Client.Framing.Impl { - public readonly ulong _deliveryTag; - public readonly bool _multiple; - public readonly bool _requeue; - - public BasicNack(ulong DeliveryTag, bool Multiple, bool Requeue) + internal readonly struct BasicNack : IOutgoingAmqpMethod { - _deliveryTag = DeliveryTag; - _multiple = Multiple; - _requeue = Requeue; - } + public readonly ulong _deliveryTag; + public readonly bool _multiple; + public readonly bool _requeue; - public BasicNack(ReadOnlySpan span) - { - int offset = WireFormatting.ReadLonglong(span, out _deliveryTag); - WireFormatting.ReadBits(span.Slice(offset), out _multiple, out _requeue); - } + public BasicNack(ulong DeliveryTag, bool Multiple, bool Requeue) + { + _deliveryTag = DeliveryTag; + _multiple = Multiple; + _requeue = Requeue; + } - public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.BasicNack; + public BasicNack(ReadOnlySpan span) + { + int offset = WireFormatting.ReadLonglong(span, out _deliveryTag); + WireFormatting.ReadBits(span.Slice(offset), out _multiple, out _requeue); + } - public int WriteTo(Span span) - { - int offset = WireFormatting.WriteLonglong(ref span.GetStart(), _deliveryTag); - return offset + WireFormatting.WriteBits(ref span.GetOffset(offset), _multiple, _requeue); - } + public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.BasicNack; - public int GetRequiredBufferSize() - { - return 8 + 1; // bytes for _deliveryTag, bit fields + public int WriteTo(Span span) + { + int offset = WireFormatting.WriteLonglong(ref span.GetStart(), _deliveryTag); + return offset + WireFormatting.WriteBits(ref span.GetOffset(offset), _multiple, _requeue); + } + + public int GetRequiredBufferSize() + { + return 8 + 1; // bytes for _deliveryTag, bit fields + } } } diff --git a/projects/RabbitMQ.Client/client/framing/BasicPublish.cs b/projects/RabbitMQ.Client/client/framing/BasicPublish.cs index 130e9975ce..9969a6a0c5 100644 --- a/projects/RabbitMQ.Client/client/framing/BasicPublish.cs +++ b/projects/RabbitMQ.Client/client/framing/BasicPublish.cs @@ -34,74 +34,75 @@ using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Impl; -namespace RabbitMQ.Client.Framing.Impl; - -internal readonly struct BasicPublish : IOutgoingAmqpMethod +namespace RabbitMQ.Client.Framing.Impl { - // deprecated - // ushort _reserved1 - public readonly string _exchange; - public readonly string _routingKey; - public readonly bool _mandatory; - public readonly bool _immediate; - - public BasicPublish(string Exchange, string RoutingKey, bool Mandatory, bool Immediate) + internal readonly struct BasicPublish : IOutgoingAmqpMethod { - _exchange = Exchange; - _routingKey = RoutingKey; - _mandatory = Mandatory; - _immediate = Immediate; - } + // deprecated + // ushort _reserved1 + public readonly string _exchange; + public readonly string _routingKey; + public readonly bool _mandatory; + public readonly bool _immediate; - public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.BasicPublish; + public BasicPublish(string Exchange, string RoutingKey, bool Mandatory, bool Immediate) + { + _exchange = Exchange; + _routingKey = RoutingKey; + _mandatory = Mandatory; + _immediate = Immediate; + } - public int WriteTo(Span span) - { - int offset = WireFormatting.WriteShort(ref span.GetStart(), default); - offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _exchange); - offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _routingKey); - return offset + WireFormatting.WriteBits(ref span.GetOffset(offset), _mandatory, _immediate); - } + public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.BasicPublish; - public int GetRequiredBufferSize() - { - int bufferSize = 2 + 1 + 1 + 1; // bytes for _reserved1, length of _exchange, length of _routingKey, bit fields - bufferSize += WireFormatting.GetByteCount(_exchange); // _exchange in bytes - bufferSize += WireFormatting.GetByteCount(_routingKey); // _routingKey in bytes - return bufferSize; - } -} + public int WriteTo(Span span) + { + int offset = WireFormatting.WriteShort(ref span.GetStart(), default); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _exchange); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _routingKey); + return offset + WireFormatting.WriteBits(ref span.GetOffset(offset), _mandatory, _immediate); + } -internal readonly struct BasicPublishMemory : IOutgoingAmqpMethod -{ - // deprecated - // ushort _reserved1 - public readonly ReadOnlyMemory _exchange; - public readonly ReadOnlyMemory _routingKey; - public readonly bool _mandatory; - public readonly bool _immediate; + public int GetRequiredBufferSize() + { + int bufferSize = 2 + 1 + 1 + 1; // bytes for _reserved1, length of _exchange, length of _routingKey, bit fields + bufferSize += WireFormatting.GetByteCount(_exchange); // _exchange in bytes + bufferSize += WireFormatting.GetByteCount(_routingKey); // _routingKey in bytes + return bufferSize; + } + } - public BasicPublishMemory(ReadOnlyMemory Exchange, ReadOnlyMemory RoutingKey, bool Mandatory, bool Immediate) + internal readonly struct BasicPublishMemory : IOutgoingAmqpMethod { - _exchange = Exchange; - _routingKey = RoutingKey; - _mandatory = Mandatory; - _immediate = Immediate; - } + // deprecated + // ushort _reserved1 + public readonly ReadOnlyMemory _exchange; + public readonly ReadOnlyMemory _routingKey; + public readonly bool _mandatory; + public readonly bool _immediate; - public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.BasicPublish; + public BasicPublishMemory(ReadOnlyMemory Exchange, ReadOnlyMemory RoutingKey, bool Mandatory, bool Immediate) + { + _exchange = Exchange; + _routingKey = RoutingKey; + _mandatory = Mandatory; + _immediate = Immediate; + } - public int WriteTo(Span span) - { - int offset = WireFormatting.WriteShort(ref span.GetStart(), default); - offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _exchange.Span); - offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _routingKey.Span); - return offset + WireFormatting.WriteBits(ref span.GetOffset(offset), _mandatory, _immediate); - } + public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.BasicPublish; - public int GetRequiredBufferSize() - { - return 2 + 1 + 1 + 1 + // bytes for _reserved1, length of _exchange, length of _routingKey, bit fields - _exchange.Length + _routingKey.Length; + public int WriteTo(Span span) + { + int offset = WireFormatting.WriteShort(ref span.GetStart(), default); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _exchange.Span); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _routingKey.Span); + return offset + WireFormatting.WriteBits(ref span.GetOffset(offset), _mandatory, _immediate); + } + + public int GetRequiredBufferSize() + { + return 2 + 1 + 1 + 1 + // bytes for _reserved1, length of _exchange, length of _routingKey, bit fields + _exchange.Length + _routingKey.Length; + } } } diff --git a/projects/RabbitMQ.Client/client/framing/BasicQos.cs b/projects/RabbitMQ.Client/client/framing/BasicQos.cs index d09a05bfc3..eea6d1f581 100644 --- a/projects/RabbitMQ.Client/client/framing/BasicQos.cs +++ b/projects/RabbitMQ.Client/client/framing/BasicQos.cs @@ -33,32 +33,33 @@ using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Impl; -namespace RabbitMQ.Client.Framing.Impl; - -internal readonly struct BasicQos : IOutgoingAmqpMethod +namespace RabbitMQ.Client.Framing.Impl { - public readonly uint _prefetchSize; - public readonly ushort _prefetchCount; - public readonly bool _global; - - public BasicQos(uint PrefetchSize, ushort PrefetchCount, bool Global) + internal readonly struct BasicQos : IOutgoingAmqpMethod { - _prefetchSize = PrefetchSize; - _prefetchCount = PrefetchCount; - _global = Global; - } + public readonly uint _prefetchSize; + public readonly ushort _prefetchCount; + public readonly bool _global; - public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.BasicQos; + public BasicQos(uint PrefetchSize, ushort PrefetchCount, bool Global) + { + _prefetchSize = PrefetchSize; + _prefetchCount = PrefetchCount; + _global = Global; + } - public int WriteTo(Span span) - { - int offset = WireFormatting.WriteLong(ref span.GetStart(), _prefetchSize); - offset += WireFormatting.WriteShort(ref span.GetOffset(offset), _prefetchCount); - return offset + WireFormatting.WriteBits(ref span.GetOffset(offset), _global); - } + public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.BasicQos; - public int GetRequiredBufferSize() - { - return 4 + 2 + 1; // bytes for _prefetchSize, _prefetchCount, bit fields + public int WriteTo(Span span) + { + int offset = WireFormatting.WriteLong(ref span.GetStart(), _prefetchSize); + offset += WireFormatting.WriteShort(ref span.GetOffset(offset), _prefetchCount); + return offset + WireFormatting.WriteBits(ref span.GetOffset(offset), _global); + } + + public int GetRequiredBufferSize() + { + return 4 + 2 + 1; // bytes for _prefetchSize, _prefetchCount, bit fields + } } } diff --git a/projects/RabbitMQ.Client/client/framing/BasicRecover.cs b/projects/RabbitMQ.Client/client/framing/BasicRecover.cs index ac3efc43e2..471e9b2274 100644 --- a/projects/RabbitMQ.Client/client/framing/BasicRecover.cs +++ b/projects/RabbitMQ.Client/client/framing/BasicRecover.cs @@ -33,26 +33,27 @@ using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Impl; -namespace RabbitMQ.Client.Framing.Impl; - -internal readonly struct BasicRecover : IOutgoingAmqpMethod +namespace RabbitMQ.Client.Framing.Impl { - public readonly bool _requeue; - - public BasicRecover(bool Requeue) + internal readonly struct BasicRecover : IOutgoingAmqpMethod { - _requeue = Requeue; - } + public readonly bool _requeue; - public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.BasicRecover; + public BasicRecover(bool Requeue) + { + _requeue = Requeue; + } - public int WriteTo(Span span) - { - return WireFormatting.WriteBits(ref span.GetStart(), _requeue); - } + public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.BasicRecover; - public int GetRequiredBufferSize() - { - return 1; // bytes for bit fields + public int WriteTo(Span span) + { + return WireFormatting.WriteBits(ref span.GetStart(), _requeue); + } + + public int GetRequiredBufferSize() + { + return 1; // bytes for bit fields + } } } diff --git a/projects/RabbitMQ.Client/client/framing/BasicRecoverAsync.cs b/projects/RabbitMQ.Client/client/framing/BasicRecoverAsync.cs index 02e1426ba1..e2c76097ea 100644 --- a/projects/RabbitMQ.Client/client/framing/BasicRecoverAsync.cs +++ b/projects/RabbitMQ.Client/client/framing/BasicRecoverAsync.cs @@ -33,26 +33,27 @@ using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Impl; -namespace RabbitMQ.Client.Framing.Impl; - -internal readonly struct BasicRecoverAsync : IOutgoingAmqpMethod +namespace RabbitMQ.Client.Framing.Impl { - public readonly bool _requeue; - - public BasicRecoverAsync(bool Requeue) + internal readonly struct BasicRecoverAsync : IOutgoingAmqpMethod { - _requeue = Requeue; - } + public readonly bool _requeue; - public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.BasicRecoverAsync; + public BasicRecoverAsync(bool Requeue) + { + _requeue = Requeue; + } - public int WriteTo(Span span) - { - return WireFormatting.WriteBits(ref span.GetStart(), _requeue); - } + public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.BasicRecoverAsync; - public int GetRequiredBufferSize() - { - return 1; // bytes for bit fields + public int WriteTo(Span span) + { + return WireFormatting.WriteBits(ref span.GetStart(), _requeue); + } + + public int GetRequiredBufferSize() + { + return 1; // bytes for bit fields + } } } diff --git a/projects/RabbitMQ.Client/client/framing/BasicReject.cs b/projects/RabbitMQ.Client/client/framing/BasicReject.cs index 84dc02cf19..74fb7b5283 100644 --- a/projects/RabbitMQ.Client/client/framing/BasicReject.cs +++ b/projects/RabbitMQ.Client/client/framing/BasicReject.cs @@ -33,29 +33,30 @@ using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Impl; -namespace RabbitMQ.Client.Framing.Impl; - -internal readonly struct BasicReject : IOutgoingAmqpMethod +namespace RabbitMQ.Client.Framing.Impl { - public readonly ulong _deliveryTag; - public readonly bool _requeue; - - public BasicReject(ulong DeliveryTag, bool Requeue) + internal readonly struct BasicReject : IOutgoingAmqpMethod { - _deliveryTag = DeliveryTag; - _requeue = Requeue; - } + public readonly ulong _deliveryTag; + public readonly bool _requeue; - public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.BasicReject; + public BasicReject(ulong DeliveryTag, bool Requeue) + { + _deliveryTag = DeliveryTag; + _requeue = Requeue; + } - public int WriteTo(Span span) - { - int offset = WireFormatting.WriteLonglong(ref span.GetStart(), _deliveryTag); - return offset + WireFormatting.WriteBits(ref span.GetOffset(offset), _requeue); - } + public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.BasicReject; - public int GetRequiredBufferSize() - { - return 8 + 1; // bytes for _deliveryTag, bit fields + public int WriteTo(Span span) + { + int offset = WireFormatting.WriteLonglong(ref span.GetStart(), _deliveryTag); + return offset + WireFormatting.WriteBits(ref span.GetOffset(offset), _requeue); + } + + public int GetRequiredBufferSize() + { + return 8 + 1; // bytes for _deliveryTag, bit fields + } } } diff --git a/projects/RabbitMQ.Client/client/framing/BasicReturn.cs b/projects/RabbitMQ.Client/client/framing/BasicReturn.cs index fdafeced6a..7d5b737c1d 100644 --- a/projects/RabbitMQ.Client/client/framing/BasicReturn.cs +++ b/projects/RabbitMQ.Client/client/framing/BasicReturn.cs @@ -34,22 +34,23 @@ using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Impl; -namespace RabbitMQ.Client.Framing.Impl; - -internal readonly struct BasicReturn : IAmqpMethod +namespace RabbitMQ.Client.Framing.Impl { - public readonly ushort _replyCode; - public readonly string _replyText; - public readonly string _exchange; - public readonly string _routingKey; - - public BasicReturn(ReadOnlySpan span) + internal readonly struct BasicReturn : IAmqpMethod { - int offset = WireFormatting.ReadShort(span, out _replyCode); - offset += WireFormatting.ReadShortstr(span.Slice(offset), out _replyText); - offset += WireFormatting.ReadShortstr(span.Slice(offset), out _exchange); - WireFormatting.ReadShortstr(span.Slice(offset), out _routingKey); - } + public readonly ushort _replyCode; + public readonly string _replyText; + public readonly string _exchange; + public readonly string _routingKey; - public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.BasicReturn; + public BasicReturn(ReadOnlySpan span) + { + int offset = WireFormatting.ReadShort(span, out _replyCode); + offset += WireFormatting.ReadShortstr(span.Slice(offset), out _replyText); + offset += WireFormatting.ReadShortstr(span.Slice(offset), out _exchange); + WireFormatting.ReadShortstr(span.Slice(offset), out _routingKey); + } + + public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.BasicReturn; + } } diff --git a/projects/RabbitMQ.Client/client/framing/ChannelClose.cs b/projects/RabbitMQ.Client/client/framing/ChannelClose.cs index 47f88240ea..3d39bd6df1 100644 --- a/projects/RabbitMQ.Client/client/framing/ChannelClose.cs +++ b/projects/RabbitMQ.Client/client/framing/ChannelClose.cs @@ -34,45 +34,46 @@ using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Impl; -namespace RabbitMQ.Client.Framing.Impl; - -internal readonly struct ChannelClose : IOutgoingAmqpMethod +namespace RabbitMQ.Client.Framing.Impl { - public readonly ushort _replyCode; - public readonly string _replyText; - public readonly ushort _classId; - public readonly ushort _methodId; - - public ChannelClose(ushort ReplyCode, string ReplyText, ushort ClassId, ushort MethodId) + internal readonly struct ChannelClose : IOutgoingAmqpMethod { - _replyCode = ReplyCode; - _replyText = ReplyText; - _classId = ClassId; - _methodId = MethodId; - } + public readonly ushort _replyCode; + public readonly string _replyText; + public readonly ushort _classId; + public readonly ushort _methodId; - public ChannelClose(ReadOnlySpan span) - { - int offset = WireFormatting.ReadShort(span, out _replyCode); - offset += WireFormatting.ReadShortstr(span.Slice(offset), out _replyText); - offset += WireFormatting.ReadShort(span.Slice(offset), out _classId); - WireFormatting.ReadShort(span.Slice(offset), out _methodId); - } + public ChannelClose(ushort ReplyCode, string ReplyText, ushort ClassId, ushort MethodId) + { + _replyCode = ReplyCode; + _replyText = ReplyText; + _classId = ClassId; + _methodId = MethodId; + } - public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ChannelClose; + public ChannelClose(ReadOnlySpan span) + { + int offset = WireFormatting.ReadShort(span, out _replyCode); + offset += WireFormatting.ReadShortstr(span.Slice(offset), out _replyText); + offset += WireFormatting.ReadShort(span.Slice(offset), out _classId); + WireFormatting.ReadShort(span.Slice(offset), out _methodId); + } - public int WriteTo(Span span) - { - int offset = WireFormatting.WriteShort(ref span.GetStart(), _replyCode); - offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _replyText); - offset += WireFormatting.WriteShort(ref span.GetOffset(offset), _classId); - return offset + WireFormatting.WriteShort(ref span.GetOffset(offset), _methodId); - } + public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ChannelClose; - public int GetRequiredBufferSize() - { - int bufferSize = 2 + 1 + 2 + 2; // bytes for _replyCode, length of _replyText, _classId, _methodId - bufferSize += WireFormatting.GetByteCount(_replyText); // _replyText in bytes - return bufferSize; + public int WriteTo(Span span) + { + int offset = WireFormatting.WriteShort(ref span.GetStart(), _replyCode); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _replyText); + offset += WireFormatting.WriteShort(ref span.GetOffset(offset), _classId); + return offset + WireFormatting.WriteShort(ref span.GetOffset(offset), _methodId); + } + + public int GetRequiredBufferSize() + { + int bufferSize = 2 + 1 + 2 + 2; // bytes for _replyCode, length of _replyText, _classId, _methodId + bufferSize += WireFormatting.GetByteCount(_replyText); // _replyText in bytes + return bufferSize; + } } } diff --git a/projects/RabbitMQ.Client/client/framing/ChannelCloseOk.cs b/projects/RabbitMQ.Client/client/framing/ChannelCloseOk.cs index 2ecbded058..bb4ebf80cf 100644 --- a/projects/RabbitMQ.Client/client/framing/ChannelCloseOk.cs +++ b/projects/RabbitMQ.Client/client/framing/ChannelCloseOk.cs @@ -32,19 +32,20 @@ using System; using RabbitMQ.Client.client.framing; -namespace RabbitMQ.Client.Framing.Impl; - -internal readonly struct ChannelCloseOk : IOutgoingAmqpMethod +namespace RabbitMQ.Client.Framing.Impl { - public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ChannelCloseOk; - - public int WriteTo(Span span) + internal readonly struct ChannelCloseOk : IOutgoingAmqpMethod { - return 0; - } + public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ChannelCloseOk; - public int GetRequiredBufferSize() - { - return 0; + public int WriteTo(Span span) + { + return 0; + } + + public int GetRequiredBufferSize() + { + return 0; + } } } diff --git a/projects/RabbitMQ.Client/client/framing/ChannelFlow.cs b/projects/RabbitMQ.Client/client/framing/ChannelFlow.cs index 86aa839103..e12f674bd2 100644 --- a/projects/RabbitMQ.Client/client/framing/ChannelFlow.cs +++ b/projects/RabbitMQ.Client/client/framing/ChannelFlow.cs @@ -33,16 +33,17 @@ using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Impl; -namespace RabbitMQ.Client.Framing.Impl; - -internal readonly struct ChannelFlow : IAmqpMethod +namespace RabbitMQ.Client.Framing.Impl { - public readonly bool _active; - - public ChannelFlow(ReadOnlySpan span) + internal readonly struct ChannelFlow : IAmqpMethod { - WireFormatting.ReadBits(span, out _active); - } + public readonly bool _active; - public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ChannelFlow; + public ChannelFlow(ReadOnlySpan span) + { + WireFormatting.ReadBits(span, out _active); + } + + public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ChannelFlow; + } } diff --git a/projects/RabbitMQ.Client/client/framing/ChannelFlowOk.cs b/projects/RabbitMQ.Client/client/framing/ChannelFlowOk.cs index 084abe0d37..45fc55d42a 100644 --- a/projects/RabbitMQ.Client/client/framing/ChannelFlowOk.cs +++ b/projects/RabbitMQ.Client/client/framing/ChannelFlowOk.cs @@ -33,26 +33,27 @@ using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Impl; -namespace RabbitMQ.Client.Framing.Impl; - -internal readonly struct ChannelFlowOk : IOutgoingAmqpMethod +namespace RabbitMQ.Client.Framing.Impl { - public readonly bool _active; - - public ChannelFlowOk(bool Active) + internal readonly struct ChannelFlowOk : IOutgoingAmqpMethod { - _active = Active; - } + public readonly bool _active; - public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ChannelFlowOk; + public ChannelFlowOk(bool Active) + { + _active = Active; + } - public int WriteTo(Span span) - { - return WireFormatting.WriteBits(ref span.GetStart(), _active); - } + public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ChannelFlowOk; - public int GetRequiredBufferSize() - { - return 1; // bytes for bit fields + public int WriteTo(Span span) + { + return WireFormatting.WriteBits(ref span.GetStart(), _active); + } + + public int GetRequiredBufferSize() + { + return 1; // bytes for bit fields + } } } diff --git a/projects/RabbitMQ.Client/client/framing/ChannelMethodConstants.cs b/projects/RabbitMQ.Client/client/framing/ChannelMethodConstants.cs index f131d5c6e8..b249e9e2b4 100644 --- a/projects/RabbitMQ.Client/client/framing/ChannelMethodConstants.cs +++ b/projects/RabbitMQ.Client/client/framing/ChannelMethodConstants.cs @@ -29,14 +29,15 @@ // Copyright (c) 2007-2020 VMware, Inc. All rights reserved. //--------------------------------------------------------------------------- -namespace RabbitMQ.Client.Framing.Impl; - -internal static class ChannelMethodConstants +namespace RabbitMQ.Client.Framing.Impl { - internal const ushort Open = 10; - internal const ushort OpenOk = 11; - internal const ushort Flow = 20; - internal const ushort FlowOk = 21; - internal const ushort Close = 40; - internal const ushort CloseOk = 41; + internal static class ChannelMethodConstants + { + internal const ushort Open = 10; + internal const ushort OpenOk = 11; + internal const ushort Flow = 20; + internal const ushort FlowOk = 21; + internal const ushort Close = 40; + internal const ushort CloseOk = 41; + } } diff --git a/projects/RabbitMQ.Client/client/framing/ChannelOpen.cs b/projects/RabbitMQ.Client/client/framing/ChannelOpen.cs index b5400edaa7..88d3fb42dd 100644 --- a/projects/RabbitMQ.Client/client/framing/ChannelOpen.cs +++ b/projects/RabbitMQ.Client/client/framing/ChannelOpen.cs @@ -32,23 +32,24 @@ using System; using RabbitMQ.Client.client.framing; -namespace RabbitMQ.Client.Framing.Impl; - -internal readonly struct ChannelOpen : IOutgoingAmqpMethod +namespace RabbitMQ.Client.Framing.Impl { - // deprecated - // string _reserved1 + internal readonly struct ChannelOpen : IOutgoingAmqpMethod + { + // deprecated + // string _reserved1 - public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ChannelOpen; + public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ChannelOpen; - public int WriteTo(Span span) - { - span[0] = 0; // _reserved1 - return 1; - } + public int WriteTo(Span span) + { + span[0] = 0; // _reserved1 + return 1; + } - public int GetRequiredBufferSize() - { - return 1; // bytes for length of _reserved1 + public int GetRequiredBufferSize() + { + return 1; // bytes for length of _reserved1 + } } } diff --git a/projects/RabbitMQ.Client/client/framing/ClassConstants.cs b/projects/RabbitMQ.Client/client/framing/ClassConstants.cs index d626eae3ab..af6b612ead 100644 --- a/projects/RabbitMQ.Client/client/framing/ClassConstants.cs +++ b/projects/RabbitMQ.Client/client/framing/ClassConstants.cs @@ -29,15 +29,16 @@ // Copyright (c) 2007-2020 VMware, Inc. All rights reserved. //--------------------------------------------------------------------------- -namespace RabbitMQ.Client.Framing.Impl; - -internal static class ClassConstants +namespace RabbitMQ.Client.Framing.Impl { - internal const ushort Connection = 10; - internal const ushort Channel = 20; - internal const ushort Exchange = 40; - internal const ushort Queue = 50; - internal const ushort Basic = 60; - internal const ushort Tx = 90; - internal const ushort Confirm = 85; + internal static class ClassConstants + { + internal const ushort Connection = 10; + internal const ushort Channel = 20; + internal const ushort Exchange = 40; + internal const ushort Queue = 50; + internal const ushort Basic = 60; + internal const ushort Tx = 90; + internal const ushort Confirm = 85; + } } diff --git a/projects/RabbitMQ.Client/client/framing/ConfirmMethodConstants.cs b/projects/RabbitMQ.Client/client/framing/ConfirmMethodConstants.cs index 9750c2ad4e..26af360347 100644 --- a/projects/RabbitMQ.Client/client/framing/ConfirmMethodConstants.cs +++ b/projects/RabbitMQ.Client/client/framing/ConfirmMethodConstants.cs @@ -29,10 +29,11 @@ // Copyright (c) 2007-2020 VMware, Inc. All rights reserved. //--------------------------------------------------------------------------- -namespace RabbitMQ.Client.Framing.Impl; - -internal static class ConfirmMethodConstants +namespace RabbitMQ.Client.Framing.Impl { - internal const ushort Select = 10; - internal const ushort SelectOk = 11; + internal static class ConfirmMethodConstants + { + internal const ushort Select = 10; + internal const ushort SelectOk = 11; + } } diff --git a/projects/RabbitMQ.Client/client/framing/ConfirmSelect.cs b/projects/RabbitMQ.Client/client/framing/ConfirmSelect.cs index e4e6085716..e3e558a35f 100644 --- a/projects/RabbitMQ.Client/client/framing/ConfirmSelect.cs +++ b/projects/RabbitMQ.Client/client/framing/ConfirmSelect.cs @@ -33,26 +33,27 @@ using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Impl; -namespace RabbitMQ.Client.Framing.Impl; - -internal readonly struct ConfirmSelect : IOutgoingAmqpMethod +namespace RabbitMQ.Client.Framing.Impl { - public readonly bool _nowait; - - public ConfirmSelect(bool Nowait) + internal readonly struct ConfirmSelect : IOutgoingAmqpMethod { - _nowait = Nowait; - } + public readonly bool _nowait; - public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ConfirmSelect; + public ConfirmSelect(bool Nowait) + { + _nowait = Nowait; + } - public int WriteTo(Span span) - { - return WireFormatting.WriteBits(ref span.GetStart(), _nowait); - } + public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ConfirmSelect; - public int GetRequiredBufferSize() - { - return 1; // bytes for bit fields + public int WriteTo(Span span) + { + return WireFormatting.WriteBits(ref span.GetStart(), _nowait); + } + + public int GetRequiredBufferSize() + { + return 1; // bytes for bit fields + } } } diff --git a/projects/RabbitMQ.Client/client/framing/ConnectionBlocked.cs b/projects/RabbitMQ.Client/client/framing/ConnectionBlocked.cs index 2bc535e191..04385bb0d6 100644 --- a/projects/RabbitMQ.Client/client/framing/ConnectionBlocked.cs +++ b/projects/RabbitMQ.Client/client/framing/ConnectionBlocked.cs @@ -34,16 +34,17 @@ using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Impl; -namespace RabbitMQ.Client.Framing.Impl; - -internal readonly struct ConnectionBlocked : IAmqpMethod +namespace RabbitMQ.Client.Framing.Impl { - public readonly string _reason; - - public ConnectionBlocked(ReadOnlySpan span) + internal readonly struct ConnectionBlocked : IAmqpMethod { - WireFormatting.ReadShortstr(span, out _reason); - } + public readonly string _reason; - public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ConnectionBlocked; + public ConnectionBlocked(ReadOnlySpan span) + { + WireFormatting.ReadShortstr(span, out _reason); + } + + public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ConnectionBlocked; + } } diff --git a/projects/RabbitMQ.Client/client/framing/ConnectionClose.cs b/projects/RabbitMQ.Client/client/framing/ConnectionClose.cs index ed62ce8353..fb9fcfc7c9 100644 --- a/projects/RabbitMQ.Client/client/framing/ConnectionClose.cs +++ b/projects/RabbitMQ.Client/client/framing/ConnectionClose.cs @@ -34,45 +34,46 @@ using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Impl; -namespace RabbitMQ.Client.Framing.Impl; - -internal readonly struct ConnectionClose : IOutgoingAmqpMethod +namespace RabbitMQ.Client.Framing.Impl { - public readonly ushort _replyCode; - public readonly string _replyText; - public readonly ushort _classId; - public readonly ushort _methodId; - - public ConnectionClose(ushort ReplyCode, string ReplyText, ushort ClassId, ushort MethodId) + internal readonly struct ConnectionClose : IOutgoingAmqpMethod { - _replyCode = ReplyCode; - _replyText = ReplyText; - _classId = ClassId; - _methodId = MethodId; - } + public readonly ushort _replyCode; + public readonly string _replyText; + public readonly ushort _classId; + public readonly ushort _methodId; - public ConnectionClose(ReadOnlySpan span) - { - int offset = WireFormatting.ReadShort(span, out _replyCode); - offset += WireFormatting.ReadShortstr(span.Slice(offset), out _replyText); - offset += WireFormatting.ReadShort(span.Slice(offset), out _classId); - WireFormatting.ReadShort(span.Slice(offset), out _methodId); - } + public ConnectionClose(ushort ReplyCode, string ReplyText, ushort ClassId, ushort MethodId) + { + _replyCode = ReplyCode; + _replyText = ReplyText; + _classId = ClassId; + _methodId = MethodId; + } - public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ConnectionClose; + public ConnectionClose(ReadOnlySpan span) + { + int offset = WireFormatting.ReadShort(span, out _replyCode); + offset += WireFormatting.ReadShortstr(span.Slice(offset), out _replyText); + offset += WireFormatting.ReadShort(span.Slice(offset), out _classId); + WireFormatting.ReadShort(span.Slice(offset), out _methodId); + } - public int WriteTo(Span span) - { - int offset = WireFormatting.WriteShort(ref span.GetStart(), _replyCode); - offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _replyText); - offset += WireFormatting.WriteShort(ref span.GetOffset(offset), _classId); - return offset + WireFormatting.WriteShort(ref span.GetOffset(offset), _methodId); - } + public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ConnectionClose; - public int GetRequiredBufferSize() - { - int bufferSize = 2 + 1 + 2 + 2; // bytes for _replyCode, length of _replyText, _classId, _methodId - bufferSize += WireFormatting.GetByteCount(_replyText); // _replyText in bytes - return bufferSize; + public int WriteTo(Span span) + { + int offset = WireFormatting.WriteShort(ref span.GetStart(), _replyCode); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _replyText); + offset += WireFormatting.WriteShort(ref span.GetOffset(offset), _classId); + return offset + WireFormatting.WriteShort(ref span.GetOffset(offset), _methodId); + } + + public int GetRequiredBufferSize() + { + int bufferSize = 2 + 1 + 2 + 2; // bytes for _replyCode, length of _replyText, _classId, _methodId + bufferSize += WireFormatting.GetByteCount(_replyText); // _replyText in bytes + return bufferSize; + } } } diff --git a/projects/RabbitMQ.Client/client/framing/ConnectionCloseOk.cs b/projects/RabbitMQ.Client/client/framing/ConnectionCloseOk.cs index ac52a8b2b4..321f7b8c3d 100644 --- a/projects/RabbitMQ.Client/client/framing/ConnectionCloseOk.cs +++ b/projects/RabbitMQ.Client/client/framing/ConnectionCloseOk.cs @@ -32,19 +32,20 @@ using System; using RabbitMQ.Client.client.framing; -namespace RabbitMQ.Client.Framing.Impl; - -internal readonly struct ConnectionCloseOk : IOutgoingAmqpMethod +namespace RabbitMQ.Client.Framing.Impl { - public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ConnectionCloseOk; - - public int WriteTo(Span span) + internal readonly struct ConnectionCloseOk : IOutgoingAmqpMethod { - return 0; - } + public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ConnectionCloseOk; - public int GetRequiredBufferSize() - { - return 0; + public int WriteTo(Span span) + { + return 0; + } + + public int GetRequiredBufferSize() + { + return 0; + } } } diff --git a/projects/RabbitMQ.Client/client/framing/ConnectionMethodConstants.cs b/projects/RabbitMQ.Client/client/framing/ConnectionMethodConstants.cs index 08c38a818e..6ec63cf72b 100644 --- a/projects/RabbitMQ.Client/client/framing/ConnectionMethodConstants.cs +++ b/projects/RabbitMQ.Client/client/framing/ConnectionMethodConstants.cs @@ -29,22 +29,23 @@ // Copyright (c) 2007-2020 VMware, Inc. All rights reserved. //--------------------------------------------------------------------------- -namespace RabbitMQ.Client.Framing.Impl; - -internal static class ConnectionMethodConstants +namespace RabbitMQ.Client.Framing.Impl { - internal const ushort Start = 10; - internal const ushort StartOk = 11; - internal const ushort Secure = 20; - internal const ushort SecureOk = 21; - internal const ushort Tune = 30; - internal const ushort TuneOk = 31; - internal const ushort Open = 40; - internal const ushort OpenOk = 41; - internal const ushort Close = 50; - internal const ushort CloseOk = 51; - internal const ushort Blocked = 60; - internal const ushort Unblocked = 61; - internal const ushort UpdateSecret = 70; - internal const ushort UpdateSecretOk = 71; + internal static class ConnectionMethodConstants + { + internal const ushort Start = 10; + internal const ushort StartOk = 11; + internal const ushort Secure = 20; + internal const ushort SecureOk = 21; + internal const ushort Tune = 30; + internal const ushort TuneOk = 31; + internal const ushort Open = 40; + internal const ushort OpenOk = 41; + internal const ushort Close = 50; + internal const ushort CloseOk = 51; + internal const ushort Blocked = 60; + internal const ushort Unblocked = 61; + internal const ushort UpdateSecret = 70; + internal const ushort UpdateSecretOk = 71; + } } diff --git a/projects/RabbitMQ.Client/client/framing/ConnectionOpen.cs b/projects/RabbitMQ.Client/client/framing/ConnectionOpen.cs index 787e1f8848..599ab9022d 100644 --- a/projects/RabbitMQ.Client/client/framing/ConnectionOpen.cs +++ b/projects/RabbitMQ.Client/client/framing/ConnectionOpen.cs @@ -34,34 +34,35 @@ using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Impl; -namespace RabbitMQ.Client.Framing.Impl; - -internal readonly struct ConnectionOpen : IOutgoingAmqpMethod +namespace RabbitMQ.Client.Framing.Impl { - public readonly string _virtualHost; - // deprecated - // string _reserved1 - // bool _reserved2 - - public ConnectionOpen(string VirtualHost) + internal readonly struct ConnectionOpen : IOutgoingAmqpMethod { - _virtualHost = VirtualHost; - } + public readonly string _virtualHost; + // deprecated + // string _reserved1 + // bool _reserved2 - public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ConnectionOpen; + public ConnectionOpen(string VirtualHost) + { + _virtualHost = VirtualHost; + } - public int WriteTo(Span span) - { - int offset = WireFormatting.WriteShortstr(ref span.GetStart(), _virtualHost); - span[offset++] = 0; // _reserved1 - span[offset++] = 0; // _reserved2 - return offset; - } + public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ConnectionOpen; - public int GetRequiredBufferSize() - { - int bufferSize = 1 + 1 + 1; // bytes for length of _virtualHost, length of _capabilities, bit fields - bufferSize += WireFormatting.GetByteCount(_virtualHost); // _virtualHost in bytes - return bufferSize; + public int WriteTo(Span span) + { + int offset = WireFormatting.WriteShortstr(ref span.GetStart(), _virtualHost); + span[offset++] = 0; // _reserved1 + span[offset++] = 0; // _reserved2 + return offset; + } + + public int GetRequiredBufferSize() + { + int bufferSize = 1 + 1 + 1; // bytes for length of _virtualHost, length of _capabilities, bit fields + bufferSize += WireFormatting.GetByteCount(_virtualHost); // _virtualHost in bytes + return bufferSize; + } } } diff --git a/projects/RabbitMQ.Client/client/framing/ConnectionSecure.cs b/projects/RabbitMQ.Client/client/framing/ConnectionSecure.cs index 96361bd19f..517e970903 100644 --- a/projects/RabbitMQ.Client/client/framing/ConnectionSecure.cs +++ b/projects/RabbitMQ.Client/client/framing/ConnectionSecure.cs @@ -33,16 +33,17 @@ using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Impl; -namespace RabbitMQ.Client.Framing.Impl; - -internal readonly struct ConnectionSecure : IAmqpMethod +namespace RabbitMQ.Client.Framing.Impl { - public readonly byte[] _challenge; - - public ConnectionSecure(ReadOnlySpan span) + internal readonly struct ConnectionSecure : IAmqpMethod { - WireFormatting.ReadLongstr(span, out _challenge); - } + public readonly byte[] _challenge; - public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ConnectionSecure; + public ConnectionSecure(ReadOnlySpan span) + { + WireFormatting.ReadLongstr(span, out _challenge); + } + + public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ConnectionSecure; + } } diff --git a/projects/RabbitMQ.Client/client/framing/ConnectionSecureOk.cs b/projects/RabbitMQ.Client/client/framing/ConnectionSecureOk.cs index 9738bef395..70c53119b3 100644 --- a/projects/RabbitMQ.Client/client/framing/ConnectionSecureOk.cs +++ b/projects/RabbitMQ.Client/client/framing/ConnectionSecureOk.cs @@ -33,28 +33,29 @@ using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Impl; -namespace RabbitMQ.Client.Framing.Impl; - -internal readonly struct ConnectionSecureOk : IOutgoingAmqpMethod +namespace RabbitMQ.Client.Framing.Impl { - public readonly byte[] _response; - - public ConnectionSecureOk(byte[] Response) + internal readonly struct ConnectionSecureOk : IOutgoingAmqpMethod { - _response = Response; - } + public readonly byte[] _response; - public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ConnectionSecureOk; + public ConnectionSecureOk(byte[] Response) + { + _response = Response; + } - public int WriteTo(Span span) - { - return WireFormatting.WriteLongstr(ref span.GetStart(), _response); - } + public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ConnectionSecureOk; - public int GetRequiredBufferSize() - { - int bufferSize = 4; // bytes for length of _response - bufferSize += _response.Length; // _response in bytes - return bufferSize; + public int WriteTo(Span span) + { + return WireFormatting.WriteLongstr(ref span.GetStart(), _response); + } + + public int GetRequiredBufferSize() + { + int bufferSize = 4; // bytes for length of _response + bufferSize += _response.Length; // _response in bytes + return bufferSize; + } } } diff --git a/projects/RabbitMQ.Client/client/framing/ConnectionStart.cs b/projects/RabbitMQ.Client/client/framing/ConnectionStart.cs index de37a43c20..841474c943 100644 --- a/projects/RabbitMQ.Client/client/framing/ConnectionStart.cs +++ b/projects/RabbitMQ.Client/client/framing/ConnectionStart.cs @@ -35,24 +35,25 @@ using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Impl; -namespace RabbitMQ.Client.Framing.Impl; - -internal readonly struct ConnectionStart : IAmqpMethod +namespace RabbitMQ.Client.Framing.Impl { - public readonly byte _versionMajor; - public readonly byte _versionMinor; - public readonly Dictionary _serverProperties; - public readonly byte[] _mechanisms; - public readonly byte[] _locales; - - public ConnectionStart(ReadOnlySpan span) + internal readonly struct ConnectionStart : IAmqpMethod { - _versionMajor = span[0]; - _versionMinor = span[1]; - int offset = 2 + WireFormatting.ReadDictionary(span.Slice(2), out _serverProperties); - offset += WireFormatting.ReadLongstr(span.Slice(offset), out _mechanisms); - WireFormatting.ReadLongstr(span.Slice(offset), out _locales); - } + public readonly byte _versionMajor; + public readonly byte _versionMinor; + public readonly Dictionary _serverProperties; + public readonly byte[] _mechanisms; + public readonly byte[] _locales; - public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ConnectionStart; + public ConnectionStart(ReadOnlySpan span) + { + _versionMajor = span[0]; + _versionMinor = span[1]; + int offset = 2 + WireFormatting.ReadDictionary(span.Slice(2), out _serverProperties); + offset += WireFormatting.ReadLongstr(span.Slice(offset), out _mechanisms); + WireFormatting.ReadLongstr(span.Slice(offset), out _locales); + } + + public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ConnectionStart; + } } diff --git a/projects/RabbitMQ.Client/client/framing/ConnectionStartOk.cs b/projects/RabbitMQ.Client/client/framing/ConnectionStartOk.cs index b453cf669d..66c322108b 100644 --- a/projects/RabbitMQ.Client/client/framing/ConnectionStartOk.cs +++ b/projects/RabbitMQ.Client/client/framing/ConnectionStartOk.cs @@ -35,40 +35,41 @@ using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Impl; -namespace RabbitMQ.Client.Framing.Impl; - -internal readonly struct ConnectionStartOk : IOutgoingAmqpMethod +namespace RabbitMQ.Client.Framing.Impl { - public readonly IDictionary _clientProperties; - public readonly string _mechanism; - public readonly byte[] _response; - public readonly string _locale; - - public ConnectionStartOk(IDictionary ClientProperties, string Mechanism, byte[] Response, string Locale) + internal readonly struct ConnectionStartOk : IOutgoingAmqpMethod { - _clientProperties = ClientProperties; - _mechanism = Mechanism; - _response = Response; - _locale = Locale; - } + public readonly IDictionary _clientProperties; + public readonly string _mechanism; + public readonly byte[] _response; + public readonly string _locale; - public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ConnectionStartOk; + public ConnectionStartOk(IDictionary ClientProperties, string Mechanism, byte[] Response, string Locale) + { + _clientProperties = ClientProperties; + _mechanism = Mechanism; + _response = Response; + _locale = Locale; + } - public int WriteTo(Span span) - { - int offset = WireFormatting.WriteTable(ref span.GetStart(), _clientProperties); - offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _mechanism); - offset += WireFormatting.WriteLongstr(ref span.GetOffset(offset), _response); - return offset + WireFormatting.WriteShortstr(ref span.GetOffset(offset), _locale); - } + public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ConnectionStartOk; - public int GetRequiredBufferSize() - { - int bufferSize = 1 + 4 + 1; // bytes for length of _mechanism, length of _response, length of _locale - bufferSize += WireFormatting.GetTableByteCount(_clientProperties); // _clientProperties in bytes - bufferSize += WireFormatting.GetByteCount(_mechanism); // _mechanism in bytes - bufferSize += _response.Length; // _response in bytes - bufferSize += WireFormatting.GetByteCount(_locale); // _locale in bytes - return bufferSize; + public int WriteTo(Span span) + { + int offset = WireFormatting.WriteTable(ref span.GetStart(), _clientProperties); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _mechanism); + offset += WireFormatting.WriteLongstr(ref span.GetOffset(offset), _response); + return offset + WireFormatting.WriteShortstr(ref span.GetOffset(offset), _locale); + } + + public int GetRequiredBufferSize() + { + int bufferSize = 1 + 4 + 1; // bytes for length of _mechanism, length of _response, length of _locale + bufferSize += WireFormatting.GetTableByteCount(_clientProperties); // _clientProperties in bytes + bufferSize += WireFormatting.GetByteCount(_mechanism); // _mechanism in bytes + bufferSize += _response.Length; // _response in bytes + bufferSize += WireFormatting.GetByteCount(_locale); // _locale in bytes + return bufferSize; + } } } diff --git a/projects/RabbitMQ.Client/client/framing/ConnectionTune.cs b/projects/RabbitMQ.Client/client/framing/ConnectionTune.cs index b63afc308e..e7813333ae 100644 --- a/projects/RabbitMQ.Client/client/framing/ConnectionTune.cs +++ b/projects/RabbitMQ.Client/client/framing/ConnectionTune.cs @@ -33,20 +33,21 @@ using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Impl; -namespace RabbitMQ.Client.Framing.Impl; - -internal readonly struct ConnectionTune : IAmqpMethod +namespace RabbitMQ.Client.Framing.Impl { - public readonly ushort _channelMax; - public readonly uint _frameMax; - public readonly ushort _heartbeat; - - public ConnectionTune(ReadOnlySpan span) + internal readonly struct ConnectionTune : IAmqpMethod { - int offset = WireFormatting.ReadShort(span, out _channelMax); - offset += WireFormatting.ReadLong(span.Slice(offset), out _frameMax); - WireFormatting.ReadShort(span.Slice(offset), out _heartbeat); - } + public readonly ushort _channelMax; + public readonly uint _frameMax; + public readonly ushort _heartbeat; - public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ConnectionTune; + public ConnectionTune(ReadOnlySpan span) + { + int offset = WireFormatting.ReadShort(span, out _channelMax); + offset += WireFormatting.ReadLong(span.Slice(offset), out _frameMax); + WireFormatting.ReadShort(span.Slice(offset), out _heartbeat); + } + + public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ConnectionTune; + } } diff --git a/projects/RabbitMQ.Client/client/framing/ConnectionTuneOk.cs b/projects/RabbitMQ.Client/client/framing/ConnectionTuneOk.cs index b87aaa5bad..f17ec31dc6 100644 --- a/projects/RabbitMQ.Client/client/framing/ConnectionTuneOk.cs +++ b/projects/RabbitMQ.Client/client/framing/ConnectionTuneOk.cs @@ -33,32 +33,33 @@ using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Impl; -namespace RabbitMQ.Client.Framing.Impl; - -internal readonly struct ConnectionTuneOk : IOutgoingAmqpMethod +namespace RabbitMQ.Client.Framing.Impl { - public readonly ushort _channelMax; - public readonly uint _frameMax; - public readonly ushort _heartbeat; - - public ConnectionTuneOk(ushort ChannelMax, uint FrameMax, ushort Heartbeat) + internal readonly struct ConnectionTuneOk : IOutgoingAmqpMethod { - _channelMax = ChannelMax; - _frameMax = FrameMax; - _heartbeat = Heartbeat; - } + public readonly ushort _channelMax; + public readonly uint _frameMax; + public readonly ushort _heartbeat; - public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ConnectionTuneOk; + public ConnectionTuneOk(ushort ChannelMax, uint FrameMax, ushort Heartbeat) + { + _channelMax = ChannelMax; + _frameMax = FrameMax; + _heartbeat = Heartbeat; + } - public int WriteTo(Span span) - { - int offset = WireFormatting.WriteShort(ref span.GetStart(), _channelMax); - offset += WireFormatting.WriteLong(ref span.GetOffset(offset), _frameMax); - return offset + WireFormatting.WriteShort(ref span.GetOffset(offset), _heartbeat); - } + public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ConnectionTuneOk; - public int GetRequiredBufferSize() - { - return 2 + 4 + 2; // bytes for _channelMax, _frameMax, _heartbeat + public int WriteTo(Span span) + { + int offset = WireFormatting.WriteShort(ref span.GetStart(), _channelMax); + offset += WireFormatting.WriteLong(ref span.GetOffset(offset), _frameMax); + return offset + WireFormatting.WriteShort(ref span.GetOffset(offset), _heartbeat); + } + + public int GetRequiredBufferSize() + { + return 2 + 4 + 2; // bytes for _channelMax, _frameMax, _heartbeat + } } } diff --git a/projects/RabbitMQ.Client/client/framing/ConnectionUpdateSecret.cs b/projects/RabbitMQ.Client/client/framing/ConnectionUpdateSecret.cs index 0ee5fcbc8e..c318136f3e 100644 --- a/projects/RabbitMQ.Client/client/framing/ConnectionUpdateSecret.cs +++ b/projects/RabbitMQ.Client/client/framing/ConnectionUpdateSecret.cs @@ -34,32 +34,33 @@ using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Impl; -namespace RabbitMQ.Client.Framing.Impl; - -internal readonly struct ConnectionUpdateSecret : IOutgoingAmqpMethod +namespace RabbitMQ.Client.Framing.Impl { - public readonly byte[] _newSecret; - public readonly string _reason; - - public ConnectionUpdateSecret(byte[] NewSecret, string Reason) + internal readonly struct ConnectionUpdateSecret : IOutgoingAmqpMethod { - _newSecret = NewSecret; - _reason = Reason; - } + public readonly byte[] _newSecret; + public readonly string _reason; - public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ConnectionUpdateSecret; + public ConnectionUpdateSecret(byte[] NewSecret, string Reason) + { + _newSecret = NewSecret; + _reason = Reason; + } - public int WriteTo(Span span) - { - int offset = WireFormatting.WriteLongstr(ref span.GetStart(), _newSecret); - return offset + WireFormatting.WriteShortstr(ref span.GetOffset(offset), _reason); - } + public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ConnectionUpdateSecret; - public int GetRequiredBufferSize() - { - int bufferSize = 4 + 1; // bytes for length of _newSecret, length of _reason - bufferSize += _newSecret.Length; // _newSecret in bytes - bufferSize += WireFormatting.GetByteCount(_reason); // _reason in bytes - return bufferSize; + public int WriteTo(Span span) + { + int offset = WireFormatting.WriteLongstr(ref span.GetStart(), _newSecret); + return offset + WireFormatting.WriteShortstr(ref span.GetOffset(offset), _reason); + } + + public int GetRequiredBufferSize() + { + int bufferSize = 4 + 1; // bytes for length of _newSecret, length of _reason + bufferSize += _newSecret.Length; // _newSecret in bytes + bufferSize += WireFormatting.GetByteCount(_reason); // _reason in bytes + return bufferSize; + } } } diff --git a/projects/RabbitMQ.Client/client/framing/Constants.cs b/projects/RabbitMQ.Client/client/framing/Constants.cs index 3c1540dde2..5d75f698f6 100644 --- a/projects/RabbitMQ.Client/client/framing/Constants.cs +++ b/projects/RabbitMQ.Client/client/framing/Constants.cs @@ -29,56 +29,57 @@ // Copyright (c) 2007-2020 VMware, Inc. All rights reserved. //--------------------------------------------------------------------------- -namespace RabbitMQ.Client; - -public static class Constants +namespace RabbitMQ.Client { - ///(= 1) - public const int FrameMethod = 1; - ///(= 2) - public const int FrameHeader = 2; - ///(= 3) - public const int FrameBody = 3; - ///(= 8) - public const int FrameHeartbeat = 8; - ///(= 4096) - public const int FrameMinSize = 4096; - ///(= 206) - public const int FrameEnd = 206; - ///(= 200) - public const int ReplySuccess = 200; - ///(= 311) - public const int ContentTooLarge = 311; - ///(= 313) - public const int NoConsumers = 313; - ///(= 320) - public const int ConnectionForced = 320; - ///(= 402) - public const int InvalidPath = 402; - ///(= 403) - public const int AccessRefused = 403; - ///(= 404) - public const int NotFound = 404; - ///(= 405) - public const int ResourceLocked = 405; - ///(= 406) - public const int PreconditionFailed = 406; - ///(= 501) - public const int FrameError = 501; - ///(= 502) - public const int SyntaxError = 502; - ///(= 503) - public const int CommandInvalid = 503; - ///(= 504) - public const int ChannelError = 504; - ///(= 505) - public const int UnexpectedFrame = 505; - ///(= 506) - public const int ResourceError = 506; - ///(= 530) - public const int NotAllowed = 530; - ///(= 540) - public const int NotImplemented = 540; - ///(= 541) - public const int InternalError = 541; + public static class Constants + { + ///(= 1) + public const int FrameMethod = 1; + ///(= 2) + public const int FrameHeader = 2; + ///(= 3) + public const int FrameBody = 3; + ///(= 8) + public const int FrameHeartbeat = 8; + ///(= 4096) + public const int FrameMinSize = 4096; + ///(= 206) + public const int FrameEnd = 206; + ///(= 200) + public const int ReplySuccess = 200; + ///(= 311) + public const int ContentTooLarge = 311; + ///(= 313) + public const int NoConsumers = 313; + ///(= 320) + public const int ConnectionForced = 320; + ///(= 402) + public const int InvalidPath = 402; + ///(= 403) + public const int AccessRefused = 403; + ///(= 404) + public const int NotFound = 404; + ///(= 405) + public const int ResourceLocked = 405; + ///(= 406) + public const int PreconditionFailed = 406; + ///(= 501) + public const int FrameError = 501; + ///(= 502) + public const int SyntaxError = 502; + ///(= 503) + public const int CommandInvalid = 503; + ///(= 504) + public const int ChannelError = 504; + ///(= 505) + public const int UnexpectedFrame = 505; + ///(= 506) + public const int ResourceError = 506; + ///(= 530) + public const int NotAllowed = 530; + ///(= 540) + public const int NotImplemented = 540; + ///(= 541) + public const int InternalError = 541; + } } diff --git a/projects/RabbitMQ.Client/client/framing/ExchangeBind.cs b/projects/RabbitMQ.Client/client/framing/ExchangeBind.cs index cacacaf3cd..3fd120e8fa 100644 --- a/projects/RabbitMQ.Client/client/framing/ExchangeBind.cs +++ b/projects/RabbitMQ.Client/client/framing/ExchangeBind.cs @@ -35,46 +35,47 @@ using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Impl; -namespace RabbitMQ.Client.Framing.Impl; - -internal readonly struct ExchangeBind : IOutgoingAmqpMethod +namespace RabbitMQ.Client.Framing.Impl { - // deprecated - // ushort _reserved1 - public readonly string _destination; - public readonly string _source; - public readonly string _routingKey; - public readonly bool _nowait; - public readonly IDictionary _arguments; - - public ExchangeBind(string Destination, string Source, string RoutingKey, bool Nowait, IDictionary Arguments) + internal readonly struct ExchangeBind : IOutgoingAmqpMethod { - _destination = Destination; - _source = Source; - _routingKey = RoutingKey; - _nowait = Nowait; - _arguments = Arguments; - } + // deprecated + // ushort _reserved1 + public readonly string _destination; + public readonly string _source; + public readonly string _routingKey; + public readonly bool _nowait; + public readonly IDictionary _arguments; - public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ExchangeBind; + public ExchangeBind(string Destination, string Source, string RoutingKey, bool Nowait, IDictionary Arguments) + { + _destination = Destination; + _source = Source; + _routingKey = RoutingKey; + _nowait = Nowait; + _arguments = Arguments; + } - public int WriteTo(Span span) - { - int offset = WireFormatting.WriteShort(ref span.GetStart(), default); - offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _destination); - offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _source); - offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _routingKey); - offset += WireFormatting.WriteBits(ref span.GetOffset(offset), _nowait); - return offset + WireFormatting.WriteTable(ref span.GetOffset(offset), _arguments); - } + public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ExchangeBind; - public int GetRequiredBufferSize() - { - int bufferSize = 2 + 1 + 1 + 1 + 1; // bytes for _reserved1, length of _destination, length of _source, length of _routingKey, bit fields - bufferSize += WireFormatting.GetByteCount(_destination); // _destination in bytes - bufferSize += WireFormatting.GetByteCount(_source); // _source in bytes - bufferSize += WireFormatting.GetByteCount(_routingKey); // _routingKey in bytes - bufferSize += WireFormatting.GetTableByteCount(_arguments); // _arguments in bytes - return bufferSize; + public int WriteTo(Span span) + { + int offset = WireFormatting.WriteShort(ref span.GetStart(), default); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _destination); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _source); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _routingKey); + offset += WireFormatting.WriteBits(ref span.GetOffset(offset), _nowait); + return offset + WireFormatting.WriteTable(ref span.GetOffset(offset), _arguments); + } + + public int GetRequiredBufferSize() + { + int bufferSize = 2 + 1 + 1 + 1 + 1; // bytes for _reserved1, length of _destination, length of _source, length of _routingKey, bit fields + bufferSize += WireFormatting.GetByteCount(_destination); // _destination in bytes + bufferSize += WireFormatting.GetByteCount(_source); // _source in bytes + bufferSize += WireFormatting.GetByteCount(_routingKey); // _routingKey in bytes + bufferSize += WireFormatting.GetTableByteCount(_arguments); // _arguments in bytes + return bufferSize; + } } } diff --git a/projects/RabbitMQ.Client/client/framing/ExchangeDeclare.cs b/projects/RabbitMQ.Client/client/framing/ExchangeDeclare.cs index 3221451d4b..25e730a218 100644 --- a/projects/RabbitMQ.Client/client/framing/ExchangeDeclare.cs +++ b/projects/RabbitMQ.Client/client/framing/ExchangeDeclare.cs @@ -35,50 +35,51 @@ using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Impl; -namespace RabbitMQ.Client.Framing.Impl; - -internal readonly struct ExchangeDeclare : IOutgoingAmqpMethod +namespace RabbitMQ.Client.Framing.Impl { - // deprecated - // ushort _reserved1 - public readonly string _exchange; - public readonly string _type; - public readonly bool _passive; - public readonly bool _durable; - public readonly bool _autoDelete; - public readonly bool _internal; - public readonly bool _nowait; - public readonly IDictionary _arguments; - - public ExchangeDeclare(string Exchange, string Type, bool Passive, bool Durable, bool AutoDelete, bool Internal, bool Nowait, IDictionary Arguments) + internal readonly struct ExchangeDeclare : IOutgoingAmqpMethod { - _exchange = Exchange; - _type = Type; - _passive = Passive; - _durable = Durable; - _autoDelete = AutoDelete; - _internal = Internal; - _nowait = Nowait; - _arguments = Arguments; - } + // deprecated + // ushort _reserved1 + public readonly string _exchange; + public readonly string _type; + public readonly bool _passive; + public readonly bool _durable; + public readonly bool _autoDelete; + public readonly bool _internal; + public readonly bool _nowait; + public readonly IDictionary _arguments; - public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ExchangeDeclare; + public ExchangeDeclare(string Exchange, string Type, bool Passive, bool Durable, bool AutoDelete, bool Internal, bool Nowait, IDictionary Arguments) + { + _exchange = Exchange; + _type = Type; + _passive = Passive; + _durable = Durable; + _autoDelete = AutoDelete; + _internal = Internal; + _nowait = Nowait; + _arguments = Arguments; + } - public int WriteTo(Span span) - { - int offset = WireFormatting.WriteShort(ref span.GetStart(), default); - offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _exchange); - offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _type); - offset += WireFormatting.WriteBits(ref span.GetOffset(offset), _passive, _durable, _autoDelete, _internal, _nowait); - return offset + WireFormatting.WriteTable(ref span.GetOffset(offset), _arguments); - } + public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ExchangeDeclare; - public int GetRequiredBufferSize() - { - int bufferSize = 2 + 1 + 1 + 1; // bytes for _reserved1, length of _exchange, length of _type, bit fields - bufferSize += WireFormatting.GetByteCount(_exchange); // _exchange in bytes - bufferSize += WireFormatting.GetByteCount(_type); // _type in bytes - bufferSize += WireFormatting.GetTableByteCount(_arguments); // _arguments in bytes - return bufferSize; + public int WriteTo(Span span) + { + int offset = WireFormatting.WriteShort(ref span.GetStart(), default); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _exchange); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _type); + offset += WireFormatting.WriteBits(ref span.GetOffset(offset), _passive, _durable, _autoDelete, _internal, _nowait); + return offset + WireFormatting.WriteTable(ref span.GetOffset(offset), _arguments); + } + + public int GetRequiredBufferSize() + { + int bufferSize = 2 + 1 + 1 + 1; // bytes for _reserved1, length of _exchange, length of _type, bit fields + bufferSize += WireFormatting.GetByteCount(_exchange); // _exchange in bytes + bufferSize += WireFormatting.GetByteCount(_type); // _type in bytes + bufferSize += WireFormatting.GetTableByteCount(_arguments); // _arguments in bytes + return bufferSize; + } } } diff --git a/projects/RabbitMQ.Client/client/framing/ExchangeDelete.cs b/projects/RabbitMQ.Client/client/framing/ExchangeDelete.cs index 9535843f68..4943798866 100644 --- a/projects/RabbitMQ.Client/client/framing/ExchangeDelete.cs +++ b/projects/RabbitMQ.Client/client/framing/ExchangeDelete.cs @@ -34,36 +34,37 @@ using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Impl; -namespace RabbitMQ.Client.Framing.Impl; - -internal readonly struct ExchangeDelete : IOutgoingAmqpMethod +namespace RabbitMQ.Client.Framing.Impl { - // deprecated - // ushort _reserved1 - public readonly string _exchange; - public readonly bool _ifUnused; - public readonly bool _nowait; - - public ExchangeDelete(string Exchange, bool IfUnused, bool Nowait) + internal readonly struct ExchangeDelete : IOutgoingAmqpMethod { - _exchange = Exchange; - _ifUnused = IfUnused; - _nowait = Nowait; - } + // deprecated + // ushort _reserved1 + public readonly string _exchange; + public readonly bool _ifUnused; + public readonly bool _nowait; - public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ExchangeDelete; + public ExchangeDelete(string Exchange, bool IfUnused, bool Nowait) + { + _exchange = Exchange; + _ifUnused = IfUnused; + _nowait = Nowait; + } - public int WriteTo(Span span) - { - int offset = WireFormatting.WriteShort(ref span.GetStart(), default); - offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _exchange); - return offset + WireFormatting.WriteBits(ref span.GetOffset(offset), _ifUnused, _nowait); - } + public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ExchangeDelete; - public int GetRequiredBufferSize() - { - int bufferSize = 2 + 1 + 1; // bytes for _reserved1, length of _exchange, bit fields - bufferSize += WireFormatting.GetByteCount(_exchange); // _exchange in bytes - return bufferSize; + public int WriteTo(Span span) + { + int offset = WireFormatting.WriteShort(ref span.GetStart(), default); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _exchange); + return offset + WireFormatting.WriteBits(ref span.GetOffset(offset), _ifUnused, _nowait); + } + + public int GetRequiredBufferSize() + { + int bufferSize = 2 + 1 + 1; // bytes for _reserved1, length of _exchange, bit fields + bufferSize += WireFormatting.GetByteCount(_exchange); // _exchange in bytes + return bufferSize; + } } } diff --git a/projects/RabbitMQ.Client/client/framing/ExchangeMethodConstants.cs b/projects/RabbitMQ.Client/client/framing/ExchangeMethodConstants.cs index 5a76205bd9..eb056cd632 100644 --- a/projects/RabbitMQ.Client/client/framing/ExchangeMethodConstants.cs +++ b/projects/RabbitMQ.Client/client/framing/ExchangeMethodConstants.cs @@ -29,16 +29,17 @@ // Copyright (c) 2007-2020 VMware, Inc. All rights reserved. //--------------------------------------------------------------------------- -namespace RabbitMQ.Client.Framing.Impl; - -internal static class ExchangeMethodConstants +namespace RabbitMQ.Client.Framing.Impl { - internal const ushort Declare = 10; - internal const ushort DeclareOk = 11; - internal const ushort Delete = 20; - internal const ushort DeleteOk = 21; - internal const ushort Bind = 30; - internal const ushort BindOk = 31; - internal const ushort Unbind = 40; - internal const ushort UnbindOk = 51; + internal static class ExchangeMethodConstants + { + internal const ushort Declare = 10; + internal const ushort DeclareOk = 11; + internal const ushort Delete = 20; + internal const ushort DeleteOk = 21; + internal const ushort Bind = 30; + internal const ushort BindOk = 31; + internal const ushort Unbind = 40; + internal const ushort UnbindOk = 51; + } } diff --git a/projects/RabbitMQ.Client/client/framing/ExchangeUnbind.cs b/projects/RabbitMQ.Client/client/framing/ExchangeUnbind.cs index 3863cff66f..fdd768e8d3 100644 --- a/projects/RabbitMQ.Client/client/framing/ExchangeUnbind.cs +++ b/projects/RabbitMQ.Client/client/framing/ExchangeUnbind.cs @@ -35,46 +35,47 @@ using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Impl; -namespace RabbitMQ.Client.Framing.Impl; - -internal readonly struct ExchangeUnbind : IOutgoingAmqpMethod +namespace RabbitMQ.Client.Framing.Impl { - // deprecated - // ushort _reserved1 - public readonly string _destination; - public readonly string _source; - public readonly string _routingKey; - public readonly bool _nowait; - public readonly IDictionary _arguments; - - public ExchangeUnbind(string Destination, string Source, string RoutingKey, bool Nowait, IDictionary Arguments) + internal readonly struct ExchangeUnbind : IOutgoingAmqpMethod { - _destination = Destination; - _source = Source; - _routingKey = RoutingKey; - _nowait = Nowait; - _arguments = Arguments; - } + // deprecated + // ushort _reserved1 + public readonly string _destination; + public readonly string _source; + public readonly string _routingKey; + public readonly bool _nowait; + public readonly IDictionary _arguments; - public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ExchangeUnbind; + public ExchangeUnbind(string Destination, string Source, string RoutingKey, bool Nowait, IDictionary Arguments) + { + _destination = Destination; + _source = Source; + _routingKey = RoutingKey; + _nowait = Nowait; + _arguments = Arguments; + } - public int WriteTo(Span span) - { - int offset = WireFormatting.WriteShort(ref span.GetStart(), default); - offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _destination); - offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _source); - offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _routingKey); - offset += WireFormatting.WriteBits(ref span.GetOffset(offset), _nowait); - return offset + WireFormatting.WriteTable(ref span.GetOffset(offset), _arguments); - } + public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.ExchangeUnbind; - public int GetRequiredBufferSize() - { - int bufferSize = 2 + 1 + 1 + 1 + 1; // bytes for _reserved1, length of _destination, length of _source, length of _routingKey, bit fields - bufferSize += WireFormatting.GetByteCount(_destination); // _destination in bytes - bufferSize += WireFormatting.GetByteCount(_source); // _source in bytes - bufferSize += WireFormatting.GetByteCount(_routingKey); // _routingKey in bytes - bufferSize += WireFormatting.GetTableByteCount(_arguments); // _arguments in bytes - return bufferSize; + public int WriteTo(Span span) + { + int offset = WireFormatting.WriteShort(ref span.GetStart(), default); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _destination); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _source); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _routingKey); + offset += WireFormatting.WriteBits(ref span.GetOffset(offset), _nowait); + return offset + WireFormatting.WriteTable(ref span.GetOffset(offset), _arguments); + } + + public int GetRequiredBufferSize() + { + int bufferSize = 2 + 1 + 1 + 1 + 1; // bytes for _reserved1, length of _destination, length of _source, length of _routingKey, bit fields + bufferSize += WireFormatting.GetByteCount(_destination); // _destination in bytes + bufferSize += WireFormatting.GetByteCount(_source); // _source in bytes + bufferSize += WireFormatting.GetByteCount(_routingKey); // _routingKey in bytes + bufferSize += WireFormatting.GetTableByteCount(_arguments); // _arguments in bytes + return bufferSize; + } } } diff --git a/projects/RabbitMQ.Client/client/framing/IAmqpMethod.cs b/projects/RabbitMQ.Client/client/framing/IAmqpMethod.cs index 90b760a7f4..550af226e4 100644 --- a/projects/RabbitMQ.Client/client/framing/IAmqpMethod.cs +++ b/projects/RabbitMQ.Client/client/framing/IAmqpMethod.cs @@ -1,12 +1,13 @@ using RabbitMQ.Client.client.framing; -namespace RabbitMQ.Client.Framing.Impl; - -internal interface IAmqpMethod +namespace RabbitMQ.Client.Framing.Impl { - ProtocolCommandId ProtocolCommandId { get; } -} + internal interface IAmqpMethod + { + ProtocolCommandId ProtocolCommandId { get; } + } -internal interface IOutgoingAmqpMethod : IAmqpMethod, IAmqpWriteable -{ + internal interface IOutgoingAmqpMethod : IAmqpMethod, IAmqpWriteable + { + } } diff --git a/projects/RabbitMQ.Client/client/framing/Model.cs b/projects/RabbitMQ.Client/client/framing/Model.cs index b81ca51590..964b4cc0c2 100644 --- a/projects/RabbitMQ.Client/client/framing/Model.cs +++ b/projects/RabbitMQ.Client/client/framing/Model.cs @@ -34,376 +34,377 @@ using RabbitMQ.Client.client.impl; using RabbitMQ.Client.Impl; -namespace RabbitMQ.Client.Framing.Impl; - -internal class Model : ModelBase +namespace RabbitMQ.Client.Framing.Impl { - public Model(ConnectionConfig config, ISession session) : base(config, session) - { - } - - public override void ConnectionTuneOk(ushort channelMax, uint frameMax, ushort heartbeat) - { - var cmd = new ConnectionTuneOk(channelMax, frameMax, heartbeat); - ModelSend(ref cmd); - } - - public override void _Private_BasicCancel(string consumerTag, bool nowait) - { - var cmd = new BasicCancel(consumerTag, nowait); - ModelSend(ref cmd); - } - - public override void _Private_BasicConsume(string queue, string consumerTag, bool noLocal, bool autoAck, bool exclusive, bool nowait, IDictionary arguments) - { - var cmd = new BasicConsume(queue, consumerTag, noLocal, autoAck, exclusive, nowait, arguments); - ModelSend(ref cmd); - } - - public override void _Private_BasicGet(string queue, bool autoAck) - { - var cmd = new BasicGet(queue, autoAck); - ModelSend(ref cmd); - } - - public override void _Private_BasicRecover(bool requeue) - { - var cmd = new BasicRecover(requeue); - ModelSend(ref cmd); - } - - public override void _Private_ChannelClose(ushort replyCode, string replyText, ushort classId, ushort methodId) + internal class Model : ModelBase { - var cmd = new ChannelClose(replyCode, replyText, classId, methodId); - ModelSend(ref cmd); - } - - public override void _Private_ChannelCloseOk() - { - var cmd = new ChannelCloseOk(); - ModelSend(ref cmd); - } - - public override void _Private_ChannelFlowOk(bool active) - { - var cmd = new ChannelFlowOk(active); - ModelSend(ref cmd); - } - - public override void _Private_ChannelOpen() - { - var cmd = new ChannelOpen(); - ModelRpc(ref cmd, ProtocolCommandId.ChannelOpenOk); - } + public Model(ConnectionConfig config, ISession session) : base(config, session) + { + } - public override void _Private_ConfirmSelect(bool nowait) - { - var method = new ConfirmSelect(nowait); - if (nowait) + public override void ConnectionTuneOk(ushort channelMax, uint frameMax, ushort heartbeat) { - ModelSend(ref method); + var cmd = new ConnectionTuneOk(channelMax, frameMax, heartbeat); + ModelSend(ref cmd); } - else + + public override void _Private_BasicCancel(string consumerTag, bool nowait) { - ModelRpc(ref method, ProtocolCommandId.ConfirmSelectOk); + var cmd = new BasicCancel(consumerTag, nowait); + ModelSend(ref cmd); } - } - public override void _Private_ConnectionCloseOk() - { - var cmd = new ConnectionCloseOk(); - ModelSend(ref cmd); - } + public override void _Private_BasicConsume(string queue, string consumerTag, bool noLocal, bool autoAck, bool exclusive, bool nowait, IDictionary arguments) + { + var cmd = new BasicConsume(queue, consumerTag, noLocal, autoAck, exclusive, nowait, arguments); + ModelSend(ref cmd); + } - public override void _Private_ConnectionOpen(string virtualHost) - { - var cmd = new ConnectionOpen(virtualHost); - ModelSend(ref cmd); - } + public override void _Private_BasicGet(string queue, bool autoAck) + { + var cmd = new BasicGet(queue, autoAck); + ModelSend(ref cmd); + } - public override void _Private_ConnectionSecureOk(byte[] response) - { - var cmd = new ConnectionSecureOk(response); - ModelSend(ref cmd); - } + public override void _Private_BasicRecover(bool requeue) + { + var cmd = new BasicRecover(requeue); + ModelSend(ref cmd); + } - public override void _Private_ConnectionStartOk(IDictionary clientProperties, string mechanism, byte[] response, string locale) - { - var cmd = new ConnectionStartOk(clientProperties, mechanism, response, locale); - ModelSend(ref cmd); - } + public override void _Private_ChannelClose(ushort replyCode, string replyText, ushort classId, ushort methodId) + { + var cmd = new ChannelClose(replyCode, replyText, classId, methodId); + ModelSend(ref cmd); + } - public override void _Private_UpdateSecret(byte[] newSecret, string reason) - { - var cmd = new ConnectionUpdateSecret(newSecret, reason); - ModelRpc(ref cmd, ProtocolCommandId.ConnectionUpdateSecretOk); - } + public override void _Private_ChannelCloseOk() + { + var cmd = new ChannelCloseOk(); + ModelSend(ref cmd); + } - public override void _Private_ExchangeBind(string destination, string source, string routingKey, bool nowait, IDictionary arguments) - { - ExchangeBind method = new ExchangeBind(destination, source, routingKey, nowait, arguments); - if (nowait) + public override void _Private_ChannelFlowOk(bool active) { - ModelSend(ref method); + var cmd = new ChannelFlowOk(active); + ModelSend(ref cmd); } - else + + public override void _Private_ChannelOpen() { - ModelRpc(ref method, ProtocolCommandId.ExchangeBindOk); + var cmd = new ChannelOpen(); + ModelRpc(ref cmd, ProtocolCommandId.ChannelOpenOk); } - } - public override void _Private_ExchangeDeclare(string exchange, string type, bool passive, bool durable, bool autoDelete, bool @internal, bool nowait, IDictionary arguments) - { - ExchangeDeclare method = new ExchangeDeclare(exchange, type, passive, durable, autoDelete, @internal, nowait, arguments); - if (nowait) + public override void _Private_ConfirmSelect(bool nowait) { - ModelSend(ref method); + var method = new ConfirmSelect(nowait); + if (nowait) + { + ModelSend(ref method); + } + else + { + ModelRpc(ref method, ProtocolCommandId.ConfirmSelectOk); + } } - else + + public override void _Private_ConnectionCloseOk() { - ModelRpc(ref method, ProtocolCommandId.ExchangeDeclareOk); + var cmd = new ConnectionCloseOk(); + ModelSend(ref cmd); } - } - public override void _Private_ExchangeDelete(string exchange, bool ifUnused, bool nowait) - { - ExchangeDelete method = new ExchangeDelete(exchange, ifUnused, nowait); - if (nowait) + public override void _Private_ConnectionOpen(string virtualHost) { - ModelSend(ref method); + var cmd = new ConnectionOpen(virtualHost); + ModelSend(ref cmd); } - else + + public override void _Private_ConnectionSecureOk(byte[] response) { - ModelRpc(ref method, ProtocolCommandId.ExchangeDeleteOk); + var cmd = new ConnectionSecureOk(response); + ModelSend(ref cmd); } - } - public override void _Private_ExchangeUnbind(string destination, string source, string routingKey, bool nowait, IDictionary arguments) - { - ExchangeUnbind method = new ExchangeUnbind(destination, source, routingKey, nowait, arguments); - if (nowait) + public override void _Private_ConnectionStartOk(IDictionary clientProperties, string mechanism, byte[] response, string locale) { - ModelSend(ref method); + var cmd = new ConnectionStartOk(clientProperties, mechanism, response, locale); + ModelSend(ref cmd); } - else + + public override void _Private_UpdateSecret(byte[] newSecret, string reason) { - ModelRpc(ref method, ProtocolCommandId.ExchangeUnbindOk); + var cmd = new ConnectionUpdateSecret(newSecret, reason); + ModelRpc(ref cmd, ProtocolCommandId.ConnectionUpdateSecretOk); } - } - public override void _Private_QueueBind(string queue, string exchange, string routingKey, bool nowait, IDictionary arguments) - { - QueueBind method = new QueueBind(queue, exchange, routingKey, nowait, arguments); - if (nowait) + public override void _Private_ExchangeBind(string destination, string source, string routingKey, bool nowait, IDictionary arguments) { - ModelSend(ref method); + ExchangeBind method = new ExchangeBind(destination, source, routingKey, nowait, arguments); + if (nowait) + { + ModelSend(ref method); + } + else + { + ModelRpc(ref method, ProtocolCommandId.ExchangeBindOk); + } } - else + + public override void _Private_ExchangeDeclare(string exchange, string type, bool passive, bool durable, bool autoDelete, bool @internal, bool nowait, IDictionary arguments) { - ModelRpc(ref method, ProtocolCommandId.QueueBindOk); + ExchangeDeclare method = new ExchangeDeclare(exchange, type, passive, durable, autoDelete, @internal, nowait, arguments); + if (nowait) + { + ModelSend(ref method); + } + else + { + ModelRpc(ref method, ProtocolCommandId.ExchangeDeclareOk); + } } - } - public override void _Private_QueueDeclare(string queue, bool passive, bool durable, bool exclusive, bool autoDelete, bool nowait, IDictionary arguments) - { - QueueDeclare method = new QueueDeclare(queue, passive, durable, exclusive, autoDelete, nowait, arguments); - if (nowait) + public override void _Private_ExchangeDelete(string exchange, bool ifUnused, bool nowait) { - ModelSend(ref method); + ExchangeDelete method = new ExchangeDelete(exchange, ifUnused, nowait); + if (nowait) + { + ModelSend(ref method); + } + else + { + ModelRpc(ref method, ProtocolCommandId.ExchangeDeleteOk); + } } - else + + public override void _Private_ExchangeUnbind(string destination, string source, string routingKey, bool nowait, IDictionary arguments) { - ModelSend(ref method); + ExchangeUnbind method = new ExchangeUnbind(destination, source, routingKey, nowait, arguments); + if (nowait) + { + ModelSend(ref method); + } + else + { + ModelRpc(ref method, ProtocolCommandId.ExchangeUnbindOk); + } } - } - public override uint _Private_QueueDelete(string queue, bool ifUnused, bool ifEmpty, bool nowait) - { - QueueDelete method = new QueueDelete(queue, ifUnused, ifEmpty, nowait); - if (nowait) + public override void _Private_QueueBind(string queue, string exchange, string routingKey, bool nowait, IDictionary arguments) { - ModelSend(ref method); - return 0xFFFFFFFF; + QueueBind method = new QueueBind(queue, exchange, routingKey, nowait, arguments); + if (nowait) + { + ModelSend(ref method); + } + else + { + ModelRpc(ref method, ProtocolCommandId.QueueBindOk); + } } - return ModelRpc(ref method, ProtocolCommandId.QueueDeleteOk, memory => new QueueDeleteOk(memory.Span)._messageCount); - } + public override void _Private_QueueDeclare(string queue, bool passive, bool durable, bool exclusive, bool autoDelete, bool nowait, IDictionary arguments) + { + QueueDeclare method = new QueueDeclare(queue, passive, durable, exclusive, autoDelete, nowait, arguments); + if (nowait) + { + ModelSend(ref method); + } + else + { + ModelSend(ref method); + } + } - public override uint _Private_QueuePurge(string queue, bool nowait) - { - QueuePurge method = new QueuePurge(queue, nowait); - if (nowait) + public override uint _Private_QueueDelete(string queue, bool ifUnused, bool ifEmpty, bool nowait) { - ModelSend(ref method); - return 0xFFFFFFFF; + QueueDelete method = new QueueDelete(queue, ifUnused, ifEmpty, nowait); + if (nowait) + { + ModelSend(ref method); + return 0xFFFFFFFF; + } + + return ModelRpc(ref method, ProtocolCommandId.QueueDeleteOk, memory => new QueueDeleteOk(memory.Span)._messageCount); } - return ModelRpc(ref method, ProtocolCommandId.QueuePurgeOk, memory => new QueuePurgeOk(memory.Span)._messageCount); - } + public override uint _Private_QueuePurge(string queue, bool nowait) + { + QueuePurge method = new QueuePurge(queue, nowait); + if (nowait) + { + ModelSend(ref method); + return 0xFFFFFFFF; + } + + return ModelRpc(ref method, ProtocolCommandId.QueuePurgeOk, memory => new QueuePurgeOk(memory.Span)._messageCount); + } - public override void BasicAck(ulong deliveryTag, bool multiple) - { - var cmd = new BasicAck(deliveryTag, multiple); - ModelSend(ref cmd); - } + public override void BasicAck(ulong deliveryTag, bool multiple) + { + var cmd = new BasicAck(deliveryTag, multiple); + ModelSend(ref cmd); + } - public override void BasicNack(ulong deliveryTag, bool multiple, bool requeue) - { - var cmd = new BasicNack(deliveryTag, multiple, requeue); - ModelSend(ref cmd); - } + public override void BasicNack(ulong deliveryTag, bool multiple, bool requeue) + { + var cmd = new BasicNack(deliveryTag, multiple, requeue); + ModelSend(ref cmd); + } - public override void BasicQos(uint prefetchSize, ushort prefetchCount, bool global) - { - var cmd = new BasicQos(prefetchSize, prefetchCount, global); - ModelRpc(ref cmd, ProtocolCommandId.BasicQosOk); - } + public override void BasicQos(uint prefetchSize, ushort prefetchCount, bool global) + { + var cmd = new BasicQos(prefetchSize, prefetchCount, global); + ModelRpc(ref cmd, ProtocolCommandId.BasicQosOk); + } - public override void BasicRecoverAsync(bool requeue) - { - var cmd = new BasicRecoverAsync(requeue); - ModelSend(ref cmd); - } + public override void BasicRecoverAsync(bool requeue) + { + var cmd = new BasicRecoverAsync(requeue); + ModelSend(ref cmd); + } - public override void BasicReject(ulong deliveryTag, bool requeue) - { - var cmd = new BasicReject(deliveryTag, requeue); - ModelSend(ref cmd); - } + public override void BasicReject(ulong deliveryTag, bool requeue) + { + var cmd = new BasicReject(deliveryTag, requeue); + ModelSend(ref cmd); + } - public override void QueueUnbind(string queue, string exchange, string routingKey, IDictionary arguments) - { - var cmd = new QueueUnbind(queue, exchange, routingKey, arguments); - ModelRpc(ref cmd, ProtocolCommandId.QueueUnbindOk); - } + public override void QueueUnbind(string queue, string exchange, string routingKey, IDictionary arguments) + { + var cmd = new QueueUnbind(queue, exchange, routingKey, arguments); + ModelRpc(ref cmd, ProtocolCommandId.QueueUnbindOk); + } - public override void TxCommit() - { - var cmd = new TxCommit(); - ModelRpc(ref cmd, ProtocolCommandId.TxCommitOk); - } + public override void TxCommit() + { + var cmd = new TxCommit(); + ModelRpc(ref cmd, ProtocolCommandId.TxCommitOk); + } - public override void TxRollback() - { - var cmd = new TxRollback(); - ModelRpc(ref cmd, ProtocolCommandId.TxRollbackOk); - } + public override void TxRollback() + { + var cmd = new TxRollback(); + ModelRpc(ref cmd, ProtocolCommandId.TxRollbackOk); + } - public override void TxSelect() - { - var cmd = new TxSelect(); - ModelRpc(ref cmd, ProtocolCommandId.TxSelectOk); - } + public override void TxSelect() + { + var cmd = new TxSelect(); + ModelRpc(ref cmd, ProtocolCommandId.TxSelectOk); + } - protected override bool DispatchAsynchronous(in IncomingCommand cmd) - { - switch (cmd.CommandId) - { - case ProtocolCommandId.BasicDeliver: - { - HandleBasicDeliver(in cmd); - return true; - } - case ProtocolCommandId.BasicAck: - { - HandleBasicAck(in cmd); - return true; - } - case ProtocolCommandId.BasicCancel: - { - HandleBasicCancel(in cmd); - return true; - } - case ProtocolCommandId.BasicCancelOk: - { - HandleBasicCancelOk(in cmd); - return true; - } - case ProtocolCommandId.BasicConsumeOk: - { - HandleBasicConsumeOk(in cmd); - return true; - } - case ProtocolCommandId.BasicGetEmpty: - { - cmd.ReturnMethodBuffer(); - HandleBasicGetEmpty(); - return true; - } - case ProtocolCommandId.BasicGetOk: - { - HandleBasicGetOk(in cmd); - return true; - } - case ProtocolCommandId.BasicNack: - { - HandleBasicNack(in cmd); - return true; - } - case ProtocolCommandId.BasicRecoverOk: - { - cmd.ReturnMethodBuffer(); - HandleBasicRecoverOk(); - return true; - } - case ProtocolCommandId.BasicReturn: - { - HandleBasicReturn(in cmd); - return true; - } - case ProtocolCommandId.ChannelClose: - { - HandleChannelClose(in cmd); - return true; - } - case ProtocolCommandId.ChannelCloseOk: - { - cmd.ReturnMethodBuffer(); - HandleChannelCloseOk(); - return true; - } - case ProtocolCommandId.ChannelFlow: - { - HandleChannelFlow(in cmd); - return true; - } - case ProtocolCommandId.ConnectionBlocked: - { - HandleConnectionBlocked(in cmd); - return true; - } - case ProtocolCommandId.ConnectionClose: - { - HandleConnectionClose(in cmd); - return true; - } - case ProtocolCommandId.ConnectionSecure: - { - HandleConnectionSecure(in cmd); - return true; - } - case ProtocolCommandId.ConnectionStart: - { - HandleConnectionStart(in cmd); - return true; - } - case ProtocolCommandId.ConnectionTune: - { - HandleConnectionTune(in cmd); - return true; - } - case ProtocolCommandId.ConnectionUnblocked: - { - cmd.ReturnMethodBuffer(); - HandleConnectionUnblocked(); - return true; - } - case ProtocolCommandId.QueueDeclareOk: - { - HandleQueueDeclareOk(in cmd); - return true; - } - default: return false; + protected override bool DispatchAsynchronous(in IncomingCommand cmd) + { + switch (cmd.CommandId) + { + case ProtocolCommandId.BasicDeliver: + { + HandleBasicDeliver(in cmd); + return true; + } + case ProtocolCommandId.BasicAck: + { + HandleBasicAck(in cmd); + return true; + } + case ProtocolCommandId.BasicCancel: + { + HandleBasicCancel(in cmd); + return true; + } + case ProtocolCommandId.BasicCancelOk: + { + HandleBasicCancelOk(in cmd); + return true; + } + case ProtocolCommandId.BasicConsumeOk: + { + HandleBasicConsumeOk(in cmd); + return true; + } + case ProtocolCommandId.BasicGetEmpty: + { + cmd.ReturnMethodBuffer(); + HandleBasicGetEmpty(); + return true; + } + case ProtocolCommandId.BasicGetOk: + { + HandleBasicGetOk(in cmd); + return true; + } + case ProtocolCommandId.BasicNack: + { + HandleBasicNack(in cmd); + return true; + } + case ProtocolCommandId.BasicRecoverOk: + { + cmd.ReturnMethodBuffer(); + HandleBasicRecoverOk(); + return true; + } + case ProtocolCommandId.BasicReturn: + { + HandleBasicReturn(in cmd); + return true; + } + case ProtocolCommandId.ChannelClose: + { + HandleChannelClose(in cmd); + return true; + } + case ProtocolCommandId.ChannelCloseOk: + { + cmd.ReturnMethodBuffer(); + HandleChannelCloseOk(); + return true; + } + case ProtocolCommandId.ChannelFlow: + { + HandleChannelFlow(in cmd); + return true; + } + case ProtocolCommandId.ConnectionBlocked: + { + HandleConnectionBlocked(in cmd); + return true; + } + case ProtocolCommandId.ConnectionClose: + { + HandleConnectionClose(in cmd); + return true; + } + case ProtocolCommandId.ConnectionSecure: + { + HandleConnectionSecure(in cmd); + return true; + } + case ProtocolCommandId.ConnectionStart: + { + HandleConnectionStart(in cmd); + return true; + } + case ProtocolCommandId.ConnectionTune: + { + HandleConnectionTune(in cmd); + return true; + } + case ProtocolCommandId.ConnectionUnblocked: + { + cmd.ReturnMethodBuffer(); + HandleConnectionUnblocked(); + return true; + } + case ProtocolCommandId.QueueDeclareOk: + { + HandleQueueDeclareOk(in cmd); + return true; + } + default: return false; + } } } } diff --git a/projects/RabbitMQ.Client/client/framing/Protocol.cs b/projects/RabbitMQ.Client/client/framing/Protocol.cs index 7099a8d94c..9f4a8d900e 100644 --- a/projects/RabbitMQ.Client/client/framing/Protocol.cs +++ b/projects/RabbitMQ.Client/client/framing/Protocol.cs @@ -34,27 +34,28 @@ using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Framing.Impl; -namespace RabbitMQ.Client.Framing; - -internal sealed class Protocol : ProtocolBase +namespace RabbitMQ.Client.Framing { - ///Protocol major version (= 0) - public override int MajorVersion => 0; + internal sealed class Protocol : ProtocolBase + { + ///Protocol major version (= 0) + public override int MajorVersion => 0; - ///Protocol minor version (= 9) - public override int MinorVersion => 9; + ///Protocol minor version (= 9) + public override int MinorVersion => 9; - ///Protocol revision (= 1) - public override int Revision => 1; + ///Protocol revision (= 1) + public override int Revision => 1; - ///Protocol API name (= :AMQP_0_9_1) - public override string ApiName => ":AMQP_0_9_1"; + ///Protocol API name (= :AMQP_0_9_1) + public override string ApiName => ":AMQP_0_9_1"; - ///Default TCP port (= 5672) - public override int DefaultPort => 5672; + ///Default TCP port (= 5672) + public override int DefaultPort => 5672; - internal override ProtocolCommandId DecodeCommandIdFrom(ReadOnlySpan span) - { - return (ProtocolCommandId)Util.NetworkOrderDeserializer.ReadUInt32(span); + internal override ProtocolCommandId DecodeCommandIdFrom(ReadOnlySpan span) + { + return (ProtocolCommandId)Util.NetworkOrderDeserializer.ReadUInt32(span); + } } } diff --git a/projects/RabbitMQ.Client/client/framing/ProtocolCommandId.cs b/projects/RabbitMQ.Client/client/framing/ProtocolCommandId.cs index 9134ff71c0..454346fdf9 100644 --- a/projects/RabbitMQ.Client/client/framing/ProtocolCommandId.cs +++ b/projects/RabbitMQ.Client/client/framing/ProtocolCommandId.cs @@ -1,71 +1,72 @@ using RabbitMQ.Client.Framing.Impl; -namespace RabbitMQ.Client.client.framing; - -internal enum ProtocolCommandId : uint +namespace RabbitMQ.Client.client.framing { - BasicQos = (ClassConstants.Basic << 16) | BasicMethodConstants.Qos, - BasicQosOk = (ClassConstants.Basic << 16) | BasicMethodConstants.QosOk, - BasicConsume = (ClassConstants.Basic << 16) | BasicMethodConstants.Consume, - BasicConsumeOk = (ClassConstants.Basic << 16) | BasicMethodConstants.ConsumeOk, - BasicCancel = (ClassConstants.Basic << 16) | BasicMethodConstants.Cancel, - BasicCancelOk = (ClassConstants.Basic << 16) | BasicMethodConstants.CancelOk, - BasicPublish = (ClassConstants.Basic << 16) | BasicMethodConstants.Publish, - BasicReturn = (ClassConstants.Basic << 16) | BasicMethodConstants.Return, - BasicDeliver = (ClassConstants.Basic << 16) | BasicMethodConstants.Deliver, - BasicGet = (ClassConstants.Basic << 16) | BasicMethodConstants.Get, - BasicGetOk = (ClassConstants.Basic << 16) | BasicMethodConstants.GetOk, - BasicGetEmpty = (ClassConstants.Basic << 16) | BasicMethodConstants.GetEmpty, - BasicAck = (ClassConstants.Basic << 16) | BasicMethodConstants.Ack, - BasicReject = (ClassConstants.Basic << 16) | BasicMethodConstants.Reject, - BasicRecoverAsync = (ClassConstants.Basic << 16) | BasicMethodConstants.RecoverAsync, - BasicRecover = (ClassConstants.Basic << 16) | BasicMethodConstants.Recover, - BasicRecoverOk = (ClassConstants.Basic << 16) | BasicMethodConstants.RecoverOk, - BasicNack = (ClassConstants.Basic << 16) | BasicMethodConstants.Nack, - ChannelOpen = (ClassConstants.Channel << 16) | ChannelMethodConstants.Open, - ChannelOpenOk = (ClassConstants.Channel << 16) | ChannelMethodConstants.OpenOk, - ChannelFlow = (ClassConstants.Channel << 16) | ChannelMethodConstants.Flow, - ChannelFlowOk = (ClassConstants.Channel << 16) | ChannelMethodConstants.FlowOk, - ChannelClose = (ClassConstants.Channel << 16) | ChannelMethodConstants.Close, - ChannelCloseOk = (ClassConstants.Channel << 16) | ChannelMethodConstants.CloseOk, - ConfirmSelect = (ClassConstants.Confirm << 16) | ConfirmMethodConstants.Select, - ConfirmSelectOk = (ClassConstants.Confirm << 16) | ConfirmMethodConstants.SelectOk, - ConnectionStart = (ClassConstants.Connection << 16) | ConnectionMethodConstants.Start, - ConnectionStartOk = (ClassConstants.Connection << 16) | ConnectionMethodConstants.StartOk, - ConnectionSecure = (ClassConstants.Connection << 16) | ConnectionMethodConstants.Secure, - ConnectionSecureOk = (ClassConstants.Connection << 16) | ConnectionMethodConstants.SecureOk, - ConnectionTune = (ClassConstants.Connection << 16) | ConnectionMethodConstants.Tune, - ConnectionTuneOk = (ClassConstants.Connection << 16) | ConnectionMethodConstants.TuneOk, - ConnectionOpen = (ClassConstants.Connection << 16) | ConnectionMethodConstants.Open, - ConnectionOpenOk = (ClassConstants.Connection << 16) | ConnectionMethodConstants.OpenOk, - ConnectionClose = (ClassConstants.Connection << 16) | ConnectionMethodConstants.Close, - ConnectionCloseOk = (ClassConstants.Connection << 16) | ConnectionMethodConstants.CloseOk, - ConnectionBlocked = (ClassConstants.Connection << 16) | ConnectionMethodConstants.Blocked, - ConnectionUnblocked = (ClassConstants.Connection << 16) | ConnectionMethodConstants.Unblocked, - ConnectionUpdateSecret = (ClassConstants.Connection << 16) | ConnectionMethodConstants.UpdateSecret, - ConnectionUpdateSecretOk = (ClassConstants.Connection << 16) | ConnectionMethodConstants.UpdateSecretOk, - ExchangeDeclare = (ClassConstants.Exchange << 16) | ExchangeMethodConstants.Declare, - ExchangeDeclareOk = (ClassConstants.Exchange << 16) | ExchangeMethodConstants.DeclareOk, - ExchangeDelete = (ClassConstants.Exchange << 16) | ExchangeMethodConstants.Delete, - ExchangeDeleteOk = (ClassConstants.Exchange << 16) | ExchangeMethodConstants.DeleteOk, - ExchangeBind = (ClassConstants.Exchange << 16) | ExchangeMethodConstants.Bind, - ExchangeBindOk = (ClassConstants.Exchange << 16) | ExchangeMethodConstants.BindOk, - ExchangeUnbind = (ClassConstants.Exchange << 16) | ExchangeMethodConstants.Unbind, - ExchangeUnbindOk = (ClassConstants.Exchange << 16) | ExchangeMethodConstants.UnbindOk, - QueueDeclare = (ClassConstants.Queue << 16) | QueueMethodConstants.Declare, - QueueDeclareOk = (ClassConstants.Queue << 16) | QueueMethodConstants.DeclareOk, - QueueBind = (ClassConstants.Queue << 16) | QueueMethodConstants.Bind, - QueueBindOk = (ClassConstants.Queue << 16) | QueueMethodConstants.BindOk, - QueueUnbind = (ClassConstants.Queue << 16) | QueueMethodConstants.Unbind, - QueueUnbindOk = (ClassConstants.Queue << 16) | QueueMethodConstants.UnbindOk, - QueuePurge = (ClassConstants.Queue << 16) | QueueMethodConstants.Purge, - QueuePurgeOk = (ClassConstants.Queue << 16) | QueueMethodConstants.PurgeOk, - QueueDelete = (ClassConstants.Queue << 16) | QueueMethodConstants.Delete, - QueueDeleteOk = (ClassConstants.Queue << 16) | QueueMethodConstants.DeleteOk, - TxSelect = (ClassConstants.Tx << 16) | TxMethodConstants.Select, - TxSelectOk = (ClassConstants.Tx << 16) | TxMethodConstants.SelectOk, - TxCommit = (ClassConstants.Tx << 16) | TxMethodConstants.Commit, - TxCommitOk = (ClassConstants.Tx << 16) | TxMethodConstants.CommitOk, - TxRollback = (ClassConstants.Tx << 16) | TxMethodConstants.Rollback, - TxRollbackOk = (ClassConstants.Tx << 16) | TxMethodConstants.RollbackOk + internal enum ProtocolCommandId : uint + { + BasicQos = (ClassConstants.Basic << 16) | BasicMethodConstants.Qos, + BasicQosOk = (ClassConstants.Basic << 16) | BasicMethodConstants.QosOk, + BasicConsume = (ClassConstants.Basic << 16) | BasicMethodConstants.Consume, + BasicConsumeOk = (ClassConstants.Basic << 16) | BasicMethodConstants.ConsumeOk, + BasicCancel = (ClassConstants.Basic << 16) | BasicMethodConstants.Cancel, + BasicCancelOk = (ClassConstants.Basic << 16) | BasicMethodConstants.CancelOk, + BasicPublish = (ClassConstants.Basic << 16) | BasicMethodConstants.Publish, + BasicReturn = (ClassConstants.Basic << 16) | BasicMethodConstants.Return, + BasicDeliver = (ClassConstants.Basic << 16) | BasicMethodConstants.Deliver, + BasicGet = (ClassConstants.Basic << 16) | BasicMethodConstants.Get, + BasicGetOk = (ClassConstants.Basic << 16) | BasicMethodConstants.GetOk, + BasicGetEmpty = (ClassConstants.Basic << 16) | BasicMethodConstants.GetEmpty, + BasicAck = (ClassConstants.Basic << 16) | BasicMethodConstants.Ack, + BasicReject = (ClassConstants.Basic << 16) | BasicMethodConstants.Reject, + BasicRecoverAsync = (ClassConstants.Basic << 16) | BasicMethodConstants.RecoverAsync, + BasicRecover = (ClassConstants.Basic << 16) | BasicMethodConstants.Recover, + BasicRecoverOk = (ClassConstants.Basic << 16) | BasicMethodConstants.RecoverOk, + BasicNack = (ClassConstants.Basic << 16) | BasicMethodConstants.Nack, + ChannelOpen = (ClassConstants.Channel << 16) | ChannelMethodConstants.Open, + ChannelOpenOk = (ClassConstants.Channel << 16) | ChannelMethodConstants.OpenOk, + ChannelFlow = (ClassConstants.Channel << 16) | ChannelMethodConstants.Flow, + ChannelFlowOk = (ClassConstants.Channel << 16) | ChannelMethodConstants.FlowOk, + ChannelClose = (ClassConstants.Channel << 16) | ChannelMethodConstants.Close, + ChannelCloseOk = (ClassConstants.Channel << 16) | ChannelMethodConstants.CloseOk, + ConfirmSelect = (ClassConstants.Confirm << 16) | ConfirmMethodConstants.Select, + ConfirmSelectOk = (ClassConstants.Confirm << 16) | ConfirmMethodConstants.SelectOk, + ConnectionStart = (ClassConstants.Connection << 16) | ConnectionMethodConstants.Start, + ConnectionStartOk = (ClassConstants.Connection << 16) | ConnectionMethodConstants.StartOk, + ConnectionSecure = (ClassConstants.Connection << 16) | ConnectionMethodConstants.Secure, + ConnectionSecureOk = (ClassConstants.Connection << 16) | ConnectionMethodConstants.SecureOk, + ConnectionTune = (ClassConstants.Connection << 16) | ConnectionMethodConstants.Tune, + ConnectionTuneOk = (ClassConstants.Connection << 16) | ConnectionMethodConstants.TuneOk, + ConnectionOpen = (ClassConstants.Connection << 16) | ConnectionMethodConstants.Open, + ConnectionOpenOk = (ClassConstants.Connection << 16) | ConnectionMethodConstants.OpenOk, + ConnectionClose = (ClassConstants.Connection << 16) | ConnectionMethodConstants.Close, + ConnectionCloseOk = (ClassConstants.Connection << 16) | ConnectionMethodConstants.CloseOk, + ConnectionBlocked = (ClassConstants.Connection << 16) | ConnectionMethodConstants.Blocked, + ConnectionUnblocked = (ClassConstants.Connection << 16) | ConnectionMethodConstants.Unblocked, + ConnectionUpdateSecret = (ClassConstants.Connection << 16) | ConnectionMethodConstants.UpdateSecret, + ConnectionUpdateSecretOk = (ClassConstants.Connection << 16) | ConnectionMethodConstants.UpdateSecretOk, + ExchangeDeclare = (ClassConstants.Exchange << 16) | ExchangeMethodConstants.Declare, + ExchangeDeclareOk = (ClassConstants.Exchange << 16) | ExchangeMethodConstants.DeclareOk, + ExchangeDelete = (ClassConstants.Exchange << 16) | ExchangeMethodConstants.Delete, + ExchangeDeleteOk = (ClassConstants.Exchange << 16) | ExchangeMethodConstants.DeleteOk, + ExchangeBind = (ClassConstants.Exchange << 16) | ExchangeMethodConstants.Bind, + ExchangeBindOk = (ClassConstants.Exchange << 16) | ExchangeMethodConstants.BindOk, + ExchangeUnbind = (ClassConstants.Exchange << 16) | ExchangeMethodConstants.Unbind, + ExchangeUnbindOk = (ClassConstants.Exchange << 16) | ExchangeMethodConstants.UnbindOk, + QueueDeclare = (ClassConstants.Queue << 16) | QueueMethodConstants.Declare, + QueueDeclareOk = (ClassConstants.Queue << 16) | QueueMethodConstants.DeclareOk, + QueueBind = (ClassConstants.Queue << 16) | QueueMethodConstants.Bind, + QueueBindOk = (ClassConstants.Queue << 16) | QueueMethodConstants.BindOk, + QueueUnbind = (ClassConstants.Queue << 16) | QueueMethodConstants.Unbind, + QueueUnbindOk = (ClassConstants.Queue << 16) | QueueMethodConstants.UnbindOk, + QueuePurge = (ClassConstants.Queue << 16) | QueueMethodConstants.Purge, + QueuePurgeOk = (ClassConstants.Queue << 16) | QueueMethodConstants.PurgeOk, + QueueDelete = (ClassConstants.Queue << 16) | QueueMethodConstants.Delete, + QueueDeleteOk = (ClassConstants.Queue << 16) | QueueMethodConstants.DeleteOk, + TxSelect = (ClassConstants.Tx << 16) | TxMethodConstants.Select, + TxSelectOk = (ClassConstants.Tx << 16) | TxMethodConstants.SelectOk, + TxCommit = (ClassConstants.Tx << 16) | TxMethodConstants.Commit, + TxCommitOk = (ClassConstants.Tx << 16) | TxMethodConstants.CommitOk, + TxRollback = (ClassConstants.Tx << 16) | TxMethodConstants.Rollback, + TxRollbackOk = (ClassConstants.Tx << 16) | TxMethodConstants.RollbackOk + } } diff --git a/projects/RabbitMQ.Client/client/framing/QueueBind.cs b/projects/RabbitMQ.Client/client/framing/QueueBind.cs index cd807c7200..1f0246b806 100644 --- a/projects/RabbitMQ.Client/client/framing/QueueBind.cs +++ b/projects/RabbitMQ.Client/client/framing/QueueBind.cs @@ -35,46 +35,47 @@ using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Impl; -namespace RabbitMQ.Client.Framing.Impl; - -internal readonly struct QueueBind : IOutgoingAmqpMethod +namespace RabbitMQ.Client.Framing.Impl { - // deprecated - // ushort _reserved1 - public readonly string _queue; - public readonly string _exchange; - public readonly string _routingKey; - public readonly bool _nowait; - public readonly IDictionary _arguments; - - public QueueBind(string Queue, string Exchange, string RoutingKey, bool Nowait, IDictionary Arguments) + internal readonly struct QueueBind : IOutgoingAmqpMethod { - _queue = Queue; - _exchange = Exchange; - _routingKey = RoutingKey; - _nowait = Nowait; - _arguments = Arguments; - } + // deprecated + // ushort _reserved1 + public readonly string _queue; + public readonly string _exchange; + public readonly string _routingKey; + public readonly bool _nowait; + public readonly IDictionary _arguments; - public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.QueueBind; + public QueueBind(string Queue, string Exchange, string RoutingKey, bool Nowait, IDictionary Arguments) + { + _queue = Queue; + _exchange = Exchange; + _routingKey = RoutingKey; + _nowait = Nowait; + _arguments = Arguments; + } - public int WriteTo(Span span) - { - int offset = WireFormatting.WriteShort(ref span.GetStart(), default); - offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _queue); - offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _exchange); - offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _routingKey); - offset += WireFormatting.WriteBits(ref span.GetOffset(offset), _nowait); - return offset + WireFormatting.WriteTable(ref span.GetOffset(offset), _arguments); - } + public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.QueueBind; - public int GetRequiredBufferSize() - { - int bufferSize = 2 + 1 + 1 + 1 + 1; // bytes for _reserved1, length of _queue, length of _exchange, length of _routingKey, bit fields - bufferSize += WireFormatting.GetByteCount(_queue); // _queue in bytes - bufferSize += WireFormatting.GetByteCount(_exchange); // _exchange in bytes - bufferSize += WireFormatting.GetByteCount(_routingKey); // _routingKey in bytes - bufferSize += WireFormatting.GetTableByteCount(_arguments); // _arguments in bytes - return bufferSize; + public int WriteTo(Span span) + { + int offset = WireFormatting.WriteShort(ref span.GetStart(), default); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _queue); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _exchange); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _routingKey); + offset += WireFormatting.WriteBits(ref span.GetOffset(offset), _nowait); + return offset + WireFormatting.WriteTable(ref span.GetOffset(offset), _arguments); + } + + public int GetRequiredBufferSize() + { + int bufferSize = 2 + 1 + 1 + 1 + 1; // bytes for _reserved1, length of _queue, length of _exchange, length of _routingKey, bit fields + bufferSize += WireFormatting.GetByteCount(_queue); // _queue in bytes + bufferSize += WireFormatting.GetByteCount(_exchange); // _exchange in bytes + bufferSize += WireFormatting.GetByteCount(_routingKey); // _routingKey in bytes + bufferSize += WireFormatting.GetTableByteCount(_arguments); // _arguments in bytes + return bufferSize; + } } } diff --git a/projects/RabbitMQ.Client/client/framing/QueueDeclare.cs b/projects/RabbitMQ.Client/client/framing/QueueDeclare.cs index 2a75bf5290..1fe6307bcf 100644 --- a/projects/RabbitMQ.Client/client/framing/QueueDeclare.cs +++ b/projects/RabbitMQ.Client/client/framing/QueueDeclare.cs @@ -35,46 +35,47 @@ using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Impl; -namespace RabbitMQ.Client.Framing.Impl; - -internal readonly struct QueueDeclare : IOutgoingAmqpMethod +namespace RabbitMQ.Client.Framing.Impl { - // deprecated - // ushort _reserved1 - public readonly string _queue; - public readonly bool _passive; - public readonly bool _durable; - public readonly bool _exclusive; - public readonly bool _autoDelete; - public readonly bool _nowait; - public readonly IDictionary _arguments; - - public QueueDeclare(string Queue, bool Passive, bool Durable, bool Exclusive, bool AutoDelete, bool Nowait, IDictionary Arguments) + internal readonly struct QueueDeclare : IOutgoingAmqpMethod { - _queue = Queue; - _passive = Passive; - _durable = Durable; - _exclusive = Exclusive; - _autoDelete = AutoDelete; - _nowait = Nowait; - _arguments = Arguments; - } + // deprecated + // ushort _reserved1 + public readonly string _queue; + public readonly bool _passive; + public readonly bool _durable; + public readonly bool _exclusive; + public readonly bool _autoDelete; + public readonly bool _nowait; + public readonly IDictionary _arguments; - public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.QueueDeclare; + public QueueDeclare(string Queue, bool Passive, bool Durable, bool Exclusive, bool AutoDelete, bool Nowait, IDictionary Arguments) + { + _queue = Queue; + _passive = Passive; + _durable = Durable; + _exclusive = Exclusive; + _autoDelete = AutoDelete; + _nowait = Nowait; + _arguments = Arguments; + } - public int WriteTo(Span span) - { - int offset = WireFormatting.WriteShort(ref span.GetStart(), default); - offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _queue); - offset += WireFormatting.WriteBits(ref span.GetOffset(offset), _passive, _durable, _exclusive, _autoDelete, _nowait); - return offset + WireFormatting.WriteTable(ref span.GetOffset(offset), _arguments); - } + public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.QueueDeclare; - public int GetRequiredBufferSize() - { - int bufferSize = 2 + 1 + 1; // bytes for _reserved1, length of _queue, bit fields - bufferSize += WireFormatting.GetByteCount(_queue); // _queue in bytes - bufferSize += WireFormatting.GetTableByteCount(_arguments); // _arguments in bytes - return bufferSize; + public int WriteTo(Span span) + { + int offset = WireFormatting.WriteShort(ref span.GetStart(), default); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _queue); + offset += WireFormatting.WriteBits(ref span.GetOffset(offset), _passive, _durable, _exclusive, _autoDelete, _nowait); + return offset + WireFormatting.WriteTable(ref span.GetOffset(offset), _arguments); + } + + public int GetRequiredBufferSize() + { + int bufferSize = 2 + 1 + 1; // bytes for _reserved1, length of _queue, bit fields + bufferSize += WireFormatting.GetByteCount(_queue); // _queue in bytes + bufferSize += WireFormatting.GetTableByteCount(_arguments); // _arguments in bytes + return bufferSize; + } } } diff --git a/projects/RabbitMQ.Client/client/framing/QueueDeclareOk.cs b/projects/RabbitMQ.Client/client/framing/QueueDeclareOk.cs index 4f5475620d..7380051330 100644 --- a/projects/RabbitMQ.Client/client/framing/QueueDeclareOk.cs +++ b/projects/RabbitMQ.Client/client/framing/QueueDeclareOk.cs @@ -34,20 +34,21 @@ using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Impl; -namespace RabbitMQ.Client.Framing.Impl; - -internal readonly struct QueueDeclareOk : IAmqpMethod +namespace RabbitMQ.Client.Framing.Impl { - public readonly string _queue; - public readonly uint _messageCount; - public readonly uint _consumerCount; - - public QueueDeclareOk(ReadOnlySpan span) + internal readonly struct QueueDeclareOk : IAmqpMethod { - int offset = WireFormatting.ReadShortstr(span, out _queue); - offset += WireFormatting.ReadLong(span.Slice(offset), out _messageCount); - WireFormatting.ReadLong(span.Slice(offset), out _consumerCount); - } + public readonly string _queue; + public readonly uint _messageCount; + public readonly uint _consumerCount; - public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.QueueDeclareOk; + public QueueDeclareOk(ReadOnlySpan span) + { + int offset = WireFormatting.ReadShortstr(span, out _queue); + offset += WireFormatting.ReadLong(span.Slice(offset), out _messageCount); + WireFormatting.ReadLong(span.Slice(offset), out _consumerCount); + } + + public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.QueueDeclareOk; + } } diff --git a/projects/RabbitMQ.Client/client/framing/QueueDelete.cs b/projects/RabbitMQ.Client/client/framing/QueueDelete.cs index e9372899d5..7a776a5336 100644 --- a/projects/RabbitMQ.Client/client/framing/QueueDelete.cs +++ b/projects/RabbitMQ.Client/client/framing/QueueDelete.cs @@ -34,38 +34,39 @@ using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Impl; -namespace RabbitMQ.Client.Framing.Impl; - -internal readonly struct QueueDelete : IOutgoingAmqpMethod +namespace RabbitMQ.Client.Framing.Impl { - // deprecated - // ushort _reserved1 - public readonly string _queue; - public readonly bool _ifUnused; - public readonly bool _ifEmpty; - public readonly bool _nowait; - - public QueueDelete(string Queue, bool IfUnused, bool IfEmpty, bool Nowait) + internal readonly struct QueueDelete : IOutgoingAmqpMethod { - _queue = Queue; - _ifUnused = IfUnused; - _ifEmpty = IfEmpty; - _nowait = Nowait; - } + // deprecated + // ushort _reserved1 + public readonly string _queue; + public readonly bool _ifUnused; + public readonly bool _ifEmpty; + public readonly bool _nowait; - public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.QueueDelete; + public QueueDelete(string Queue, bool IfUnused, bool IfEmpty, bool Nowait) + { + _queue = Queue; + _ifUnused = IfUnused; + _ifEmpty = IfEmpty; + _nowait = Nowait; + } - public int WriteTo(Span span) - { - int offset = WireFormatting.WriteShort(ref span.GetStart(), default); - offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _queue); - return offset + WireFormatting.WriteBits(ref span.GetOffset(offset), _ifUnused, _ifEmpty, _nowait); - } + public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.QueueDelete; - public int GetRequiredBufferSize() - { - int bufferSize = 2 + 1 + 1; // bytes for _reserved1, length of _queue, bit fields - bufferSize += WireFormatting.GetByteCount(_queue); // _queue in bytes - return bufferSize; + public int WriteTo(Span span) + { + int offset = WireFormatting.WriteShort(ref span.GetStart(), default); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _queue); + return offset + WireFormatting.WriteBits(ref span.GetOffset(offset), _ifUnused, _ifEmpty, _nowait); + } + + public int GetRequiredBufferSize() + { + int bufferSize = 2 + 1 + 1; // bytes for _reserved1, length of _queue, bit fields + bufferSize += WireFormatting.GetByteCount(_queue); // _queue in bytes + return bufferSize; + } } } diff --git a/projects/RabbitMQ.Client/client/framing/QueueDeleteOk.cs b/projects/RabbitMQ.Client/client/framing/QueueDeleteOk.cs index dbab034741..ff4b1612fa 100644 --- a/projects/RabbitMQ.Client/client/framing/QueueDeleteOk.cs +++ b/projects/RabbitMQ.Client/client/framing/QueueDeleteOk.cs @@ -33,16 +33,17 @@ using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Impl; -namespace RabbitMQ.Client.Framing.Impl; - -internal readonly struct QueueDeleteOk : IAmqpMethod +namespace RabbitMQ.Client.Framing.Impl { - public readonly uint _messageCount; - - public QueueDeleteOk(ReadOnlySpan span) + internal readonly struct QueueDeleteOk : IAmqpMethod { - WireFormatting.ReadLong(span, out _messageCount); - } + public readonly uint _messageCount; - public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.QueueDeleteOk; + public QueueDeleteOk(ReadOnlySpan span) + { + WireFormatting.ReadLong(span, out _messageCount); + } + + public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.QueueDeleteOk; + } } diff --git a/projects/RabbitMQ.Client/client/framing/QueueMethodConstants.cs b/projects/RabbitMQ.Client/client/framing/QueueMethodConstants.cs index 0035877174..6395e8aab9 100644 --- a/projects/RabbitMQ.Client/client/framing/QueueMethodConstants.cs +++ b/projects/RabbitMQ.Client/client/framing/QueueMethodConstants.cs @@ -29,18 +29,19 @@ // Copyright (c) 2007-2020 VMware, Inc. All rights reserved. //--------------------------------------------------------------------------- -namespace RabbitMQ.Client.Framing.Impl; - -internal static class QueueMethodConstants +namespace RabbitMQ.Client.Framing.Impl { - internal const ushort Declare = 10; - internal const ushort DeclareOk = 11; - internal const ushort Bind = 20; - internal const ushort BindOk = 21; - internal const ushort Unbind = 50; - internal const ushort UnbindOk = 51; - internal const ushort Purge = 30; - internal const ushort PurgeOk = 31; - internal const ushort Delete = 40; - internal const ushort DeleteOk = 41; + internal static class QueueMethodConstants + { + internal const ushort Declare = 10; + internal const ushort DeclareOk = 11; + internal const ushort Bind = 20; + internal const ushort BindOk = 21; + internal const ushort Unbind = 50; + internal const ushort UnbindOk = 51; + internal const ushort Purge = 30; + internal const ushort PurgeOk = 31; + internal const ushort Delete = 40; + internal const ushort DeleteOk = 41; + } } diff --git a/projects/RabbitMQ.Client/client/framing/QueuePurge.cs b/projects/RabbitMQ.Client/client/framing/QueuePurge.cs index 0b9c194b92..d589d8ee24 100644 --- a/projects/RabbitMQ.Client/client/framing/QueuePurge.cs +++ b/projects/RabbitMQ.Client/client/framing/QueuePurge.cs @@ -34,34 +34,35 @@ using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Impl; -namespace RabbitMQ.Client.Framing.Impl; - -internal readonly struct QueuePurge : IOutgoingAmqpMethod +namespace RabbitMQ.Client.Framing.Impl { - // deprecated - // ushort _reserved1 - public readonly string _queue; - public readonly bool _nowait; - - public QueuePurge(string Queue, bool Nowait) + internal readonly struct QueuePurge : IOutgoingAmqpMethod { - _queue = Queue; - _nowait = Nowait; - } + // deprecated + // ushort _reserved1 + public readonly string _queue; + public readonly bool _nowait; - public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.QueuePurge; + public QueuePurge(string Queue, bool Nowait) + { + _queue = Queue; + _nowait = Nowait; + } - public int WriteTo(Span span) - { - int offset = WireFormatting.WriteShort(ref span.GetStart(), default); - offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _queue); - return offset + WireFormatting.WriteBits(ref span.GetOffset(offset), _nowait); - } + public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.QueuePurge; - public int GetRequiredBufferSize() - { - int bufferSize = 2 + 1 + 1; // bytes for _reserved1, length of _queue, bit fields - bufferSize += WireFormatting.GetByteCount(_queue); // _queue in bytes - return bufferSize; + public int WriteTo(Span span) + { + int offset = WireFormatting.WriteShort(ref span.GetStart(), default); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _queue); + return offset + WireFormatting.WriteBits(ref span.GetOffset(offset), _nowait); + } + + public int GetRequiredBufferSize() + { + int bufferSize = 2 + 1 + 1; // bytes for _reserved1, length of _queue, bit fields + bufferSize += WireFormatting.GetByteCount(_queue); // _queue in bytes + return bufferSize; + } } } diff --git a/projects/RabbitMQ.Client/client/framing/QueuePurgeOk.cs b/projects/RabbitMQ.Client/client/framing/QueuePurgeOk.cs index 25b86d7a3a..465181bf74 100644 --- a/projects/RabbitMQ.Client/client/framing/QueuePurgeOk.cs +++ b/projects/RabbitMQ.Client/client/framing/QueuePurgeOk.cs @@ -33,16 +33,17 @@ using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Impl; -namespace RabbitMQ.Client.Framing.Impl; - -internal readonly struct QueuePurgeOk : IAmqpMethod +namespace RabbitMQ.Client.Framing.Impl { - public readonly uint _messageCount; - - public QueuePurgeOk(ReadOnlySpan span) + internal readonly struct QueuePurgeOk : IAmqpMethod { - WireFormatting.ReadLong(span, out _messageCount); - } + public readonly uint _messageCount; - public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.QueuePurgeOk; + public QueuePurgeOk(ReadOnlySpan span) + { + WireFormatting.ReadLong(span, out _messageCount); + } + + public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.QueuePurgeOk; + } } diff --git a/projects/RabbitMQ.Client/client/framing/QueueUnbind.cs b/projects/RabbitMQ.Client/client/framing/QueueUnbind.cs index 94af6fdf59..40fc505ed0 100644 --- a/projects/RabbitMQ.Client/client/framing/QueueUnbind.cs +++ b/projects/RabbitMQ.Client/client/framing/QueueUnbind.cs @@ -35,43 +35,44 @@ using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Impl; -namespace RabbitMQ.Client.Framing.Impl; - -internal readonly struct QueueUnbind : IOutgoingAmqpMethod +namespace RabbitMQ.Client.Framing.Impl { - // deprecated - // ushort _reserved1 - public readonly string _queue; - public readonly string _exchange; - public readonly string _routingKey; - public readonly IDictionary _arguments; - - public QueueUnbind(string Queue, string Exchange, string RoutingKey, IDictionary Arguments) + internal readonly struct QueueUnbind : IOutgoingAmqpMethod { - _queue = Queue; - _exchange = Exchange; - _routingKey = RoutingKey; - _arguments = Arguments; - } + // deprecated + // ushort _reserved1 + public readonly string _queue; + public readonly string _exchange; + public readonly string _routingKey; + public readonly IDictionary _arguments; - public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.QueueUnbind; + public QueueUnbind(string Queue, string Exchange, string RoutingKey, IDictionary Arguments) + { + _queue = Queue; + _exchange = Exchange; + _routingKey = RoutingKey; + _arguments = Arguments; + } - public int WriteTo(Span span) - { - int offset = WireFormatting.WriteShort(ref span.GetStart(), default); - offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _queue); - offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _exchange); - offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _routingKey); - return offset + WireFormatting.WriteTable(ref span.GetOffset(offset), _arguments); - } + public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.QueueUnbind; - public int GetRequiredBufferSize() - { - int bufferSize = 2 + 1 + 1 + 1; // bytes for _reserved1, length of _queue, length of _exchange, length of _routingKey - bufferSize += WireFormatting.GetByteCount(_queue); // _queue in bytes - bufferSize += WireFormatting.GetByteCount(_exchange); // _exchange in bytes - bufferSize += WireFormatting.GetByteCount(_routingKey); // _routingKey in bytes - bufferSize += WireFormatting.GetTableByteCount(_arguments); // _arguments in bytes - return bufferSize; + public int WriteTo(Span span) + { + int offset = WireFormatting.WriteShort(ref span.GetStart(), default); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _queue); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _exchange); + offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _routingKey); + return offset + WireFormatting.WriteTable(ref span.GetOffset(offset), _arguments); + } + + public int GetRequiredBufferSize() + { + int bufferSize = 2 + 1 + 1 + 1; // bytes for _reserved1, length of _queue, length of _exchange, length of _routingKey + bufferSize += WireFormatting.GetByteCount(_queue); // _queue in bytes + bufferSize += WireFormatting.GetByteCount(_exchange); // _exchange in bytes + bufferSize += WireFormatting.GetByteCount(_routingKey); // _routingKey in bytes + bufferSize += WireFormatting.GetTableByteCount(_arguments); // _arguments in bytes + return bufferSize; + } } } diff --git a/projects/RabbitMQ.Client/client/framing/TxCommit.cs b/projects/RabbitMQ.Client/client/framing/TxCommit.cs index dbf20cd910..013999fa5f 100644 --- a/projects/RabbitMQ.Client/client/framing/TxCommit.cs +++ b/projects/RabbitMQ.Client/client/framing/TxCommit.cs @@ -32,19 +32,20 @@ using System; using RabbitMQ.Client.client.framing; -namespace RabbitMQ.Client.Framing.Impl; - -internal readonly struct TxCommit : IOutgoingAmqpMethod +namespace RabbitMQ.Client.Framing.Impl { - public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.TxCommit; - - public int WriteTo(Span span) + internal readonly struct TxCommit : IOutgoingAmqpMethod { - return 0; - } + public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.TxCommit; - public int GetRequiredBufferSize() - { - return 0; + public int WriteTo(Span span) + { + return 0; + } + + public int GetRequiredBufferSize() + { + return 0; + } } } diff --git a/projects/RabbitMQ.Client/client/framing/TxMethodConstants.cs b/projects/RabbitMQ.Client/client/framing/TxMethodConstants.cs index 3241e122d3..1497b49246 100644 --- a/projects/RabbitMQ.Client/client/framing/TxMethodConstants.cs +++ b/projects/RabbitMQ.Client/client/framing/TxMethodConstants.cs @@ -29,14 +29,15 @@ // Copyright (c) 2007-2020 VMware, Inc. All rights reserved. //--------------------------------------------------------------------------- -namespace RabbitMQ.Client.Framing.Impl; - -internal static class TxMethodConstants +namespace RabbitMQ.Client.Framing.Impl { - internal const ushort Select = 10; - internal const ushort SelectOk = 11; - internal const ushort Commit = 20; - internal const ushort CommitOk = 21; - internal const ushort Rollback = 30; - internal const ushort RollbackOk = 31; + internal static class TxMethodConstants + { + internal const ushort Select = 10; + internal const ushort SelectOk = 11; + internal const ushort Commit = 20; + internal const ushort CommitOk = 21; + internal const ushort Rollback = 30; + internal const ushort RollbackOk = 31; + } } diff --git a/projects/RabbitMQ.Client/client/framing/TxRollback.cs b/projects/RabbitMQ.Client/client/framing/TxRollback.cs index a1d827a63c..027713b6e4 100644 --- a/projects/RabbitMQ.Client/client/framing/TxRollback.cs +++ b/projects/RabbitMQ.Client/client/framing/TxRollback.cs @@ -32,19 +32,20 @@ using System; using RabbitMQ.Client.client.framing; -namespace RabbitMQ.Client.Framing.Impl; - -internal readonly struct TxRollback : IOutgoingAmqpMethod +namespace RabbitMQ.Client.Framing.Impl { - public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.TxRollback; - - public int WriteTo(Span span) + internal readonly struct TxRollback : IOutgoingAmqpMethod { - return 0; - } + public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.TxRollback; - public int GetRequiredBufferSize() - { - return 0; + public int WriteTo(Span span) + { + return 0; + } + + public int GetRequiredBufferSize() + { + return 0; + } } } diff --git a/projects/RabbitMQ.Client/client/framing/TxSelect.cs b/projects/RabbitMQ.Client/client/framing/TxSelect.cs index f598023268..dd0ea866fe 100644 --- a/projects/RabbitMQ.Client/client/framing/TxSelect.cs +++ b/projects/RabbitMQ.Client/client/framing/TxSelect.cs @@ -32,19 +32,20 @@ using System; using RabbitMQ.Client.client.framing; -namespace RabbitMQ.Client.Framing.Impl; - -internal readonly struct TxSelect : IOutgoingAmqpMethod +namespace RabbitMQ.Client.Framing.Impl { - public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.TxSelect; - - public int WriteTo(Span span) + internal readonly struct TxSelect : IOutgoingAmqpMethod { - return 0; - } + public ProtocolCommandId ProtocolCommandId => ProtocolCommandId.TxSelect; - public int GetRequiredBufferSize() - { - return 0; + public int WriteTo(Span span) + { + return 0; + } + + public int GetRequiredBufferSize() + { + return 0; + } } } diff --git a/projects/RabbitMQ.Client/client/impl/AmqpVersion.cs b/projects/RabbitMQ.Client/client/impl/AmqpVersion.cs index c6b2382a8c..f0d10d80a3 100644 --- a/projects/RabbitMQ.Client/client/impl/AmqpVersion.cs +++ b/projects/RabbitMQ.Client/client/impl/AmqpVersion.cs @@ -31,87 +31,88 @@ using System; -namespace RabbitMQ.Client.Framing.Impl; - -/// Represents a version of the AMQP specification. -/// -/// -/// Vendor-specific variants of particular official specification -/// versions exist: this class simply represents the AMQP -/// specification version, and does not try to represent -/// information about any custom variations involved. -/// -/// -/// AMQP version 0-8 peers sometimes advertise themselves as -/// version 8-0: for this reason, this class's constructor -/// special-cases 8-0, rewriting it at construction time to be 0-8 instead. -/// -/// -internal readonly struct AmqpVersion : IEquatable +namespace RabbitMQ.Client.Framing.Impl { - /// - /// Construct an from major and minor version numbers. - /// + /// Represents a version of the AMQP specification. /// - /// Converts major=8 and minor=0 into major=0 and minor=8. Please see the class comment. + /// + /// Vendor-specific variants of particular official specification + /// versions exist: this class simply represents the AMQP + /// specification version, and does not try to represent + /// information about any custom variations involved. + /// + /// + /// AMQP version 0-8 peers sometimes advertise themselves as + /// version 8-0: for this reason, this class's constructor + /// special-cases 8-0, rewriting it at construction time to be 0-8 instead. + /// /// - public AmqpVersion(int major, int minor) + internal readonly struct AmqpVersion : IEquatable { - if (major == 8 && minor == 0) + /// + /// Construct an from major and minor version numbers. + /// + /// + /// Converts major=8 and minor=0 into major=0 and minor=8. Please see the class comment. + /// + public AmqpVersion(int major, int minor) { - // The AMQP 0-8 spec confusingly defines the version - // as 8-0. This maps the latter to the former, for - // cases where our peer might be confused. - major = 0; - minor = 8; + if (major == 8 && minor == 0) + { + // The AMQP 0-8 spec confusingly defines the version + // as 8-0. This maps the latter to the former, for + // cases where our peer might be confused. + major = 0; + minor = 8; + } + Major = major; + Minor = minor; } - Major = major; - Minor = minor; - } - /// - /// The AMQP specification major version number. - /// - public int Major { get; } + /// + /// The AMQP specification major version number. + /// + public int Major { get; } - /// - /// The AMQP specification minor version number. - /// - public int Minor { get; } + /// + /// The AMQP specification minor version number. + /// + public int Minor { get; } - /// - /// Implement value-equality comparison. - /// - public override bool Equals(object other) - { - return other is AmqpVersion version && Equals(version); - } + /// + /// Implement value-equality comparison. + /// + public override bool Equals(object other) + { + return other is AmqpVersion version && Equals(version); + } - public bool Equals(AmqpVersion other) => Major == other.Major && Minor == other.Minor; + public bool Equals(AmqpVersion other) => Major == other.Major && Minor == other.Minor; - public static bool operator ==(AmqpVersion left, AmqpVersion right) => left.Equals(right); + public static bool operator ==(AmqpVersion left, AmqpVersion right) => left.Equals(right); - public static bool operator !=(AmqpVersion left, AmqpVersion right) => !left.Equals(right); + public static bool operator !=(AmqpVersion left, AmqpVersion right) => !left.Equals(right); - /// - /// Implement hashing as for value-equality. - /// - public override int GetHashCode() - { - unchecked + /// + /// Implement hashing as for value-equality. + /// + public override int GetHashCode() { - return (Major * 397) ^ Minor; + unchecked + { + return (Major * 397) ^ Minor; + } } - } - /// - /// Format appropriately for display. - /// - /// - /// The specification currently uses "MAJOR-MINOR" as a display format. - /// - public override string ToString() - { - return $"{Major}-{Minor}"; + /// + /// Format appropriately for display. + /// + /// + /// The specification currently uses "MAJOR-MINOR" as a display format. + /// + public override string ToString() + { + return $"{Major}-{Minor}"; + } } } diff --git a/projects/RabbitMQ.Client/client/impl/AutorecoveringConnection.Recording.cs b/projects/RabbitMQ.Client/client/impl/AutorecoveringConnection.Recording.cs index c51ff93440..609730aefa 100644 --- a/projects/RabbitMQ.Client/client/impl/AutorecoveringConnection.Recording.cs +++ b/projects/RabbitMQ.Client/client/impl/AutorecoveringConnection.Recording.cs @@ -33,224 +33,225 @@ using System.Linq; using RabbitMQ.Client.Impl; -namespace RabbitMQ.Client.Framing.Impl; - -#nullable enable -internal sealed partial class AutorecoveringConnection +namespace RabbitMQ.Client.Framing.Impl { - private readonly object _recordedEntitiesLock = new object(); - private readonly Dictionary _recordedExchanges = new Dictionary(); - private readonly Dictionary _recordedQueues = new Dictionary(); - private readonly HashSet _recordedBindings = new HashSet(); - private readonly Dictionary _recordedConsumers = new Dictionary(); - private readonly List _models = new List(); +#nullable enable + internal sealed partial class AutorecoveringConnection + { + private readonly object _recordedEntitiesLock = new object(); + private readonly Dictionary _recordedExchanges = new Dictionary(); + private readonly Dictionary _recordedQueues = new Dictionary(); + private readonly HashSet _recordedBindings = new HashSet(); + private readonly Dictionary _recordedConsumers = new Dictionary(); + private readonly List _models = new List(); - internal int RecordedExchangesCount => _recordedExchanges.Count; + internal int RecordedExchangesCount => _recordedExchanges.Count; - internal void RecordExchange(in RecordedExchange exchange) - { - lock (_recordedEntitiesLock) + internal void RecordExchange(in RecordedExchange exchange) { - _recordedExchanges[exchange.Name] = exchange; + lock (_recordedEntitiesLock) + { + _recordedExchanges[exchange.Name] = exchange; + } } - } - internal void DeleteRecordedExchange(string exchangeName) - { - lock (_recordedEntitiesLock) + internal void DeleteRecordedExchange(string exchangeName) { - _recordedExchanges.Remove(exchangeName); - - // find bindings that need removal, check if some auto-delete exchanges might need the same - foreach (RecordedBinding binding in _recordedBindings.ToArray()) + lock (_recordedEntitiesLock) { - if (binding.Destination == exchangeName) + _recordedExchanges.Remove(exchangeName); + + // find bindings that need removal, check if some auto-delete exchanges might need the same + foreach (RecordedBinding binding in _recordedBindings.ToArray()) { - DeleteRecordedBinding(binding); - DeleteAutoDeleteExchange(binding.Source); + if (binding.Destination == exchangeName) + { + DeleteRecordedBinding(binding); + DeleteAutoDeleteExchange(binding.Source); + } } } } - } - internal void DeleteAutoDeleteExchange(string exchangeName) - { - lock (_recordedEntitiesLock) + internal void DeleteAutoDeleteExchange(string exchangeName) { - if (_recordedExchanges.TryGetValue(exchangeName, out var recordedExchange) && recordedExchange.IsAutoDelete) + lock (_recordedEntitiesLock) { - if (!AnyBindingsOnExchange(exchangeName)) + if (_recordedExchanges.TryGetValue(exchangeName, out var recordedExchange) && recordedExchange.IsAutoDelete) { - // last binding where this exchange is the source is gone, remove recorded exchange if it is auto-deleted. - DeleteRecordedExchange(exchangeName); + if (!AnyBindingsOnExchange(exchangeName)) + { + // last binding where this exchange is the source is gone, remove recorded exchange if it is auto-deleted. + _recordedExchanges.Remove(exchangeName); + } } } - } - bool AnyBindingsOnExchange(string exchange) - { - foreach (var recordedBinding in _recordedBindings) + bool AnyBindingsOnExchange(string exchange) { - if (recordedBinding.Source == exchange) + foreach (var recordedBinding in _recordedBindings) { - return true; + if (recordedBinding.Source == exchange) + { + return true; + } } - } - return false; + return false; + } } - } - internal int RecordedQueuesCount => _recordedQueues.Count; + internal int RecordedQueuesCount => _recordedQueues.Count; - internal void RecordQueue(in RecordedQueue queue) - { - lock (_recordedEntitiesLock) + internal void RecordQueue(in RecordedQueue queue) { - _recordedQueues[queue.Name] = queue; + lock (_recordedEntitiesLock) + { + _recordedQueues[queue.Name] = queue; + } } - } - internal void DeleteRecordedQueue(string queueName) - { - lock (_recordedEntitiesLock) + internal void DeleteRecordedQueue(string queueName) { - _recordedQueues.Remove(queueName); - - // find bindings that need removal, check if some auto-delete exchanges might need the same - foreach (var binding in _recordedBindings.ToArray()) + lock (_recordedEntitiesLock) { - if (binding.Destination == queueName) + _recordedQueues.Remove(queueName); + + // find bindings that need removal, check if some auto-delete exchanges might need the same + foreach (var binding in _recordedBindings.ToArray()) { - DeleteRecordedBinding(binding); - DeleteAutoDeleteExchange(binding.Source); + if (binding.Destination == queueName) + { + DeleteRecordedBinding(binding); + DeleteAutoDeleteExchange(binding.Source); + } } } } - } - private void UpdateBindingsDestination(string oldName, string newName) - { - lock (_recordedEntitiesLock) + private void UpdateBindingsDestination(string oldName, string newName) { - foreach (RecordedBinding b in _recordedBindings.ToArray()) + lock (_recordedEntitiesLock) { - if (b.Destination == oldName) + foreach (RecordedBinding b in _recordedBindings.ToArray()) { - _recordedBindings.Remove(b); - _recordedBindings.Add(new RecordedBinding(newName, b)); + if (b.Destination == oldName) + { + _recordedBindings.Remove(b); + _recordedBindings.Add(new RecordedBinding(newName, b)); + } } } } - } - private void UpdateConsumerQueue(string oldName, string newName) - { - lock (_recordedEntitiesLock) + private void UpdateConsumerQueue(string oldName, string newName) { - foreach (RecordedConsumer consumer in _recordedConsumers.Values.ToArray()) + lock (_recordedEntitiesLock) { - if (consumer.Queue == oldName) + foreach (RecordedConsumer consumer in _recordedConsumers.Values.ToArray()) { - _recordedConsumers[consumer.ConsumerTag] = RecordedConsumer.WithNewQueueNameTag(newName, consumer); + if (consumer.Queue == oldName) + { + _recordedConsumers[consumer.ConsumerTag] = RecordedConsumer.WithNewQueueNameTag(newName, consumer); + } } } } - } - internal void RecordBinding(in RecordedBinding rb) - { - lock (_recordedEntitiesLock) - { - _recordedBindings.Add(rb); - } - } - - internal void DeleteRecordedBinding(in RecordedBinding rb) - { - lock (_recordedEntitiesLock) + internal void RecordBinding(in RecordedBinding rb) { - _recordedBindings.Remove(rb); + lock (_recordedEntitiesLock) + { + _recordedBindings.Add(rb); + } } - } - internal void RecordConsumer(in RecordedConsumer consumer) - { - if (!_config.TopologyRecoveryEnabled) + internal void DeleteRecordedBinding(in RecordedBinding rb) { - return; + lock (_recordedEntitiesLock) + { + _recordedBindings.Remove(rb); + } } - lock (_recordedEntitiesLock) + internal void RecordConsumer(in RecordedConsumer consumer) { - _recordedConsumers[consumer.ConsumerTag] = consumer; - } - } + if (!_config.TopologyRecoveryEnabled) + { + return; + } - internal void DeleteRecordedConsumer(string consumerTag) - { - if (!_config.TopologyRecoveryEnabled) - { - return; + lock (_recordedEntitiesLock) + { + _recordedConsumers[consumer.ConsumerTag] = consumer; + } } - lock (_recordedEntitiesLock) + internal void DeleteRecordedConsumer(string consumerTag) { - if (_recordedConsumers.Remove(consumerTag, out var recordedConsumer)) + if (!_config.TopologyRecoveryEnabled) { - DeleteAutoDeleteQueue(recordedConsumer.Queue); + return; } - } - void DeleteAutoDeleteQueue(string queue) - { - if (_recordedQueues.TryGetValue(queue, out var recordedQueue) && recordedQueue.IsAutoDelete) + lock (_recordedEntitiesLock) { - // last consumer on this connection is gone, remove recorded queue if it is auto-deleted. - if (!AnyConsumersOnQueue(queue)) + if (_recordedConsumers.Remove(consumerTag, out var recordedConsumer)) { - DeleteRecordedQueue(queue); + DeleteAutoDeleteQueue(recordedConsumer.Queue); } } - } - bool AnyConsumersOnQueue(string queue) - { - foreach (var pair in _recordedConsumers) + void DeleteAutoDeleteQueue(string queue) { - if (pair.Value.Queue == queue) + if (_recordedQueues.TryGetValue(queue, out var recordedQueue) && recordedQueue.IsAutoDelete) { - return true; + // last consumer on this connection is gone, remove recorded queue if it is auto-deleted. + if (!AnyConsumersOnQueue(queue)) + { + _recordedQueues.Remove(queue); + } } } - return false; + bool AnyConsumersOnQueue(string queue) + { + foreach (var pair in _recordedConsumers) + { + if (pair.Value.Queue == queue) + { + return true; + } + } + + return false; + } } - } - private void UpdateConsumer(string oldTag, string newTag, in RecordedConsumer consumer) - { - lock (_recordedEntitiesLock) + private void UpdateConsumer(string oldTag, string newTag, in RecordedConsumer consumer) { - // make sure server-generated tags are re-added - _recordedConsumers.Remove(oldTag); - _recordedConsumers.Add(newTag, consumer); + lock (_recordedEntitiesLock) + { + // make sure server-generated tags are re-added + _recordedConsumers.Remove(oldTag); + _recordedConsumers.Add(newTag, consumer); + } } - } - private void RecordChannel(AutorecoveringModel m) - { - lock (_models) + private void RecordChannel(AutorecoveringModel m) { - _models.Add(m); + lock (_models) + { + _models.Add(m); + } } - } - internal void DeleteRecordedChannel(AutorecoveringModel model) - { - lock (_models) + internal void DeleteRecordedChannel(AutorecoveringModel model) { - _models.Remove(model); + lock (_models) + { + _models.Remove(model); + } } } } diff --git a/projects/RabbitMQ.Client/client/impl/AutorecoveringConnection.Recovery.cs b/projects/RabbitMQ.Client/client/impl/AutorecoveringConnection.Recovery.cs index 2151b30579..eea21f3f58 100644 --- a/projects/RabbitMQ.Client/client/impl/AutorecoveringConnection.Recovery.cs +++ b/projects/RabbitMQ.Client/client/impl/AutorecoveringConnection.Recovery.cs @@ -38,281 +38,282 @@ using RabbitMQ.Client.Impl; using RabbitMQ.Client.Logging; -namespace RabbitMQ.Client.Framing.Impl; - -#nullable enable -internal sealed partial class AutorecoveringConnection +namespace RabbitMQ.Client.Framing.Impl { - private Task? _recoveryTask; - private CancellationTokenSource? _recoveryCancellationTokenSource; +#nullable enable + internal sealed partial class AutorecoveringConnection + { + private Task? _recoveryTask; + private CancellationTokenSource? _recoveryCancellationTokenSource; - private CancellationTokenSource RecoveryCancellationTokenSource => _recoveryCancellationTokenSource ??= new CancellationTokenSource(); + private CancellationTokenSource RecoveryCancellationTokenSource => _recoveryCancellationTokenSource ??= new CancellationTokenSource(); - private void HandleConnectionShutdown(object _, ShutdownEventArgs args) - { - if (ShouldTriggerConnectionRecovery(args)) + private void HandleConnectionShutdown(object _, ShutdownEventArgs args) { - var recoverTask = new Task(RecoverConnectionAsync); - if (Interlocked.CompareExchange(ref _recoveryTask, recoverTask.Unwrap(), null) is null) + if (ShouldTriggerConnectionRecovery(args)) { - recoverTask.Start(); + var recoverTask = new Task(RecoverConnectionAsync); + if (Interlocked.CompareExchange(ref _recoveryTask, recoverTask.Unwrap(), null) is null) + { + recoverTask.Start(); + } } - } - static bool ShouldTriggerConnectionRecovery(ShutdownEventArgs args) => - args.Initiator == ShutdownInitiator.Peer || - // happens when EOF is reached, e.g. due to RabbitMQ node - // connectivity loss or abrupt shutdown - args.Initiator == ShutdownInitiator.Library; - } + static bool ShouldTriggerConnectionRecovery(ShutdownEventArgs args) => + args.Initiator == ShutdownInitiator.Peer || + // happens when EOF is reached, e.g. due to RabbitMQ node + // connectivity loss or abrupt shutdown + args.Initiator == ShutdownInitiator.Library; + } - private async Task RecoverConnectionAsync() - { - try + private async Task RecoverConnectionAsync() { - var token = RecoveryCancellationTokenSource.Token; - bool success; - do + try { - await Task.Delay(_config.NetworkRecoveryInterval, token).ConfigureAwait(false); - success = TryPerformAutomaticRecovery(); - } while (!success && !token.IsCancellationRequested); - } - catch (OperationCanceledException) - { - // expected when recovery cancellation token is set. - } - catch (Exception e) - { - ESLog.Error("Main recovery loop threw unexpected exception.", e); - } - - // clear recovery task - _recoveryTask = null; - } + var token = RecoveryCancellationTokenSource.Token; + bool success; + do + { + await Task.Delay(_config.NetworkRecoveryInterval, token).ConfigureAwait(false); + success = TryPerformAutomaticRecovery(); + } while (!success && !token.IsCancellationRequested); + } + catch (OperationCanceledException) + { + // expected when recovery cancellation token is set. + } + catch (Exception e) + { + ESLog.Error("Main recovery loop threw unexpected exception.", e); + } - /// - /// Cancels the main recovery loop and will block until the loop finishes, or the timeout - /// expires, to prevent Close operations overlapping with recovery operations. - /// - private void StopRecoveryLoop() - { - var task = _recoveryTask; - if (task is null) - { - return; + // clear recovery task + _recoveryTask = null; } - RecoveryCancellationTokenSource.Cancel(); - Task timeout = Task.Delay(_config.RequestedConnectionTimeout); - if (Task.WhenAny(task, timeout).Result == timeout) + /// + /// Cancels the main recovery loop and will block until the loop finishes, or the timeout + /// expires, to prevent Close operations overlapping with recovery operations. + /// + private void StopRecoveryLoop() { - ESLog.Warn("Timeout while trying to stop background AutorecoveringConnection recovery loop."); + var task = _recoveryTask; + if (task is null) + { + return; + } + RecoveryCancellationTokenSource.Cancel(); + + Task timeout = Task.Delay(_config.RequestedConnectionTimeout); + if (Task.WhenAny(task, timeout).Result == timeout) + { + ESLog.Warn("Timeout while trying to stop background AutorecoveringConnection recovery loop."); + } } - } - private static void HandleTopologyRecoveryException(TopologyRecoveryException e) - { - ESLog.Error("Topology recovery exception", e); - if (e.InnerException is AlreadyClosedException || - (e.InnerException is OperationInterruptedException) || - (e.InnerException is TimeoutException)) + private static void HandleTopologyRecoveryException(TopologyRecoveryException e) { - throw e; + ESLog.Error("Topology recovery exception", e); + if (e.InnerException is AlreadyClosedException || + (e.InnerException is OperationInterruptedException) || + (e.InnerException is TimeoutException)) + { + throw e; + } + ESLog.Info($"Will not retry recovery because of {e.InnerException?.GetType().FullName}: it's not a known problem with connectivity, ignoring it", e); } - ESLog.Info($"Will not retry recovery because of {e.InnerException?.GetType().FullName}: it's not a known problem with connectivity, ignoring it", e); - } - - private bool TryPerformAutomaticRecovery() - { - ESLog.Info("Performing automatic recovery"); - try + private bool TryPerformAutomaticRecovery() { - ThrowIfDisposed(); - if (TryRecoverConnectionDelegate()) + ESLog.Info("Performing automatic recovery"); + + try { - lock (_recordedEntitiesLock) + ThrowIfDisposed(); + if (TryRecoverConnectionDelegate()) { - ThrowIfDisposed(); - if (_config.TopologyRecoveryEnabled) + lock (_recordedEntitiesLock) { - // The recovery sequence is the following: - // - // 1. Recover exchanges - // 2. Recover queues - // 3. Recover bindings - // 4. Recover consumers - using (var recoveryChannel = _innerConnection.CreateModel()) + ThrowIfDisposed(); + if (_config.TopologyRecoveryEnabled) { - RecoverExchanges(recoveryChannel); - RecoverQueues(recoveryChannel); - RecoverBindings(recoveryChannel); - } + // The recovery sequence is the following: + // + // 1. Recover exchanges + // 2. Recover queues + // 3. Recover bindings + // 4. Recover consumers + using (var recoveryChannel = _innerConnection.CreateModel()) + { + RecoverExchanges(recoveryChannel); + RecoverQueues(recoveryChannel); + RecoverBindings(recoveryChannel); + } + } + RecoverModelsAndItsConsumers(); } - RecoverModelsAndItsConsumers(); - } - ESLog.Info("Connection recovery completed"); - ThrowIfDisposed(); - _recoverySucceededWrapper.Invoke(this, EventArgs.Empty); + ESLog.Info("Connection recovery completed"); + ThrowIfDisposed(); + _recoverySucceededWrapper.Invoke(this, EventArgs.Empty); - return true; - } + return true; + } - ESLog.Warn("Connection delegate was manually closed. Aborted recovery."); - } - catch (Exception e) - { - ESLog.Error("Exception when recovering connection. Will try again after retry interval.", e); - try + ESLog.Warn("Connection delegate was manually closed. Aborted recovery."); + } + catch (Exception e) { - /* - * To prevent connection leaks on the next recovery loop, - * we abort the delegated connection if it is still open. - * We do not want to block the abort forever (potentially deadlocking recovery), - * so we specify the same configured timeout used for connection. - */ - if (_innerConnection?.IsOpen == true) + ESLog.Error("Exception when recovering connection. Will try again after retry interval.", e); + try { - _innerConnection.Abort(Constants.InternalError, "FailedAutoRecovery", _config.RequestedConnectionTimeout); + /* + * To prevent connection leaks on the next recovery loop, + * we abort the delegated connection if it is still open. + * We do not want to block the abort forever (potentially deadlocking recovery), + * so we specify the same configured timeout used for connection. + */ + if (_innerConnection?.IsOpen == true) + { + _innerConnection.Abort(Constants.InternalError, "FailedAutoRecovery", _config.RequestedConnectionTimeout); + } + } + catch (Exception e2) + { + ESLog.Warn("Exception when aborting previous auto recovery connection.", e2); } } - catch (Exception e2) - { - ESLog.Warn("Exception when aborting previous auto recovery connection.", e2); - } - } - return false; - } - - private bool TryRecoverConnectionDelegate() - { - try - { - var defunctConnection = _innerConnection; - IFrameHandler fh = _endpoints.SelectOne(_config.FrameHandlerFactory); - _innerConnection = new Connection(_config, fh); - _innerConnection.TakeOver(defunctConnection); - return true; - } - catch (Exception e) - { - ESLog.Error("Connection recovery exception.", e); - // Trigger recovery error events - if (!_connectionRecoveryErrorWrapper.IsEmpty) - { - _connectionRecoveryErrorWrapper.Invoke(this, new ConnectionRecoveryErrorEventArgs(e)); - } + return false; } - return false; - } - - private void RecoverExchanges(IModel channel) - { - foreach (var recordedExchange in _recordedExchanges.Values) + private bool TryRecoverConnectionDelegate() { try { - recordedExchange.Recover(channel); + var defunctConnection = _innerConnection; + IFrameHandler fh = _endpoints.SelectOne(_config.FrameHandlerFactory); + _innerConnection = new Connection(_config, fh); + _innerConnection.TakeOver(defunctConnection); + return true; } - catch (Exception ex) + catch (Exception e) { - HandleTopologyRecoveryException(new TopologyRecoveryException($"Caught an exception while recovering exchange '{recordedExchange}'", ex)); + ESLog.Error("Connection recovery exception.", e); + // Trigger recovery error events + if (!_connectionRecoveryErrorWrapper.IsEmpty) + { + _connectionRecoveryErrorWrapper.Invoke(this, new ConnectionRecoveryErrorEventArgs(e)); + } } + + return false; } - } - private void RecoverQueues(IModel channel) - { - foreach (var recordedQueue in _recordedQueues.Values.ToArray()) + private void RecoverExchanges(IModel channel) { - try + foreach (var recordedExchange in _recordedExchanges.Values) { - var newName = recordedQueue.Recover(channel); - var oldName = recordedQueue.Name; + try + { + recordedExchange.Recover(channel); + } + catch (Exception ex) + { + HandleTopologyRecoveryException(new TopologyRecoveryException($"Caught an exception while recovering exchange '{recordedExchange}'", ex)); + } + } + } - if (oldName != newName) + private void RecoverQueues(IModel channel) + { + foreach (var recordedQueue in _recordedQueues.Values.ToArray()) + { + try { - // Make sure server-named queues are re-added with their new names. - // We only remove old name after we've updated the bindings and consumers, - // plus only for server-named queues, both to make sure we don't lose - // anything to recover. MK. - UpdateBindingsDestination(oldName, newName); - UpdateConsumerQueue(oldName, newName); + var newName = recordedQueue.Recover(channel); + var oldName = recordedQueue.Name; - // see rabbitmq/rabbitmq-dotnet-client#43 - if (recordedQueue.IsServerNamed) + if (oldName != newName) { - DeleteRecordedQueue(oldName); - } - RecordQueue(new RecordedQueue(newName, recordedQueue)); + // Make sure server-named queues are re-added with their new names. + // We only remove old name after we've updated the bindings and consumers, + // plus only for server-named queues, both to make sure we don't lose + // anything to recover. MK. + UpdateBindingsDestination(oldName, newName); + UpdateConsumerQueue(oldName, newName); - if (!_queueNameChangeAfterRecoveryWrapper.IsEmpty) - { - _queueNameChangeAfterRecoveryWrapper.Invoke(this, new QueueNameChangedAfterRecoveryEventArgs(oldName, newName)); + // see rabbitmq/rabbitmq-dotnet-client#43 + if (recordedQueue.IsServerNamed) + { + DeleteRecordedQueue(oldName); + } + RecordQueue(new RecordedQueue(newName, recordedQueue)); + + if (!_queueNameChangeAfterRecoveryWrapper.IsEmpty) + { + _queueNameChangeAfterRecoveryWrapper.Invoke(this, new QueueNameChangedAfterRecoveryEventArgs(oldName, newName)); + } } } - } - catch (Exception ex) - { - HandleTopologyRecoveryException(new TopologyRecoveryException($"Caught an exception while recovering queue '{recordedQueue}'", ex)); + catch (Exception ex) + { + HandleTopologyRecoveryException(new TopologyRecoveryException($"Caught an exception while recovering queue '{recordedQueue}'", ex)); + } } } - } - private void RecoverBindings(IModel channel) - { - foreach (var binding in _recordedBindings) + private void RecoverBindings(IModel channel) { - try + foreach (var binding in _recordedBindings) { - binding.Recover(channel); - } - catch (Exception ex) - { - HandleTopologyRecoveryException(new TopologyRecoveryException($"Caught an exception while recovering binding between {binding.Source} and {binding.Destination}", ex)); + try + { + binding.Recover(channel); + } + catch (Exception ex) + { + HandleTopologyRecoveryException(new TopologyRecoveryException($"Caught an exception while recovering binding between {binding.Source} and {binding.Destination}", ex)); + } } } - } - internal void RecoverConsumers(AutorecoveringModel channelToRecover, IModel channelToUse) - { - foreach (var consumer in _recordedConsumers.Values.ToArray()) + internal void RecoverConsumers(AutorecoveringModel channelToRecover, IModel channelToUse) { - if (consumer.Channel != channelToRecover) + foreach (var consumer in _recordedConsumers.Values.ToArray()) { - continue; - } + if (consumer.Channel != channelToRecover) + { + continue; + } - var oldTag = consumer.ConsumerTag; - try - { - var newTag = consumer.Recover(channelToUse); - UpdateConsumer(oldTag, newTag, RecordedConsumer.WithNewConsumerTag(newTag, consumer)); + var oldTag = consumer.ConsumerTag; + try + { + var newTag = consumer.Recover(channelToUse); + UpdateConsumer(oldTag, newTag, RecordedConsumer.WithNewConsumerTag(newTag, consumer)); - if (!_consumerTagChangeAfterRecoveryWrapper.IsEmpty) + if (!_consumerTagChangeAfterRecoveryWrapper.IsEmpty) + { + _consumerTagChangeAfterRecoveryWrapper.Invoke(this, new ConsumerTagChangedAfterRecoveryEventArgs(oldTag, newTag)); + } + } + catch (Exception ex) { - _consumerTagChangeAfterRecoveryWrapper.Invoke(this, new ConsumerTagChangedAfterRecoveryEventArgs(oldTag, newTag)); + HandleTopologyRecoveryException(new TopologyRecoveryException($"Caught an exception while recovering consumer {oldTag} on queue {consumer.Queue}", ex)); } } - catch (Exception ex) - { - HandleTopologyRecoveryException(new TopologyRecoveryException($"Caught an exception while recovering consumer {oldTag} on queue {consumer.Queue}", ex)); - } } - } - private void RecoverModelsAndItsConsumers() - { - lock (_models) + private void RecoverModelsAndItsConsumers() { - foreach (AutorecoveringModel m in _models) + lock (_models) { - m.AutomaticallyRecover(this, _config.TopologyRecoveryEnabled); + foreach (AutorecoveringModel m in _models) + { + m.AutomaticallyRecover(this, _config.TopologyRecoveryEnabled); + } } } } diff --git a/projects/RabbitMQ.Client/client/impl/AutorecoveringConnection.cs b/projects/RabbitMQ.Client/client/impl/AutorecoveringConnection.cs index 3222c4974b..7a66e01441 100644 --- a/projects/RabbitMQ.Client/client/impl/AutorecoveringConnection.cs +++ b/projects/RabbitMQ.Client/client/impl/AutorecoveringConnection.cs @@ -35,203 +35,204 @@ using RabbitMQ.Client.Events; using RabbitMQ.Client.Impl; -namespace RabbitMQ.Client.Framing.Impl; - -internal sealed partial class AutorecoveringConnection : IConnection +namespace RabbitMQ.Client.Framing.Impl { - private readonly ConnectionConfig _config; - // list of endpoints provided on initial connection. - // on re-connection, the next host in the line is chosen using - // IHostnameSelector - private readonly IEndpointResolver _endpoints; + internal sealed partial class AutorecoveringConnection : IConnection + { + private readonly ConnectionConfig _config; + // list of endpoints provided on initial connection. + // on re-connection, the next host in the line is chosen using + // IHostnameSelector + private readonly IEndpointResolver _endpoints; - private Connection _innerConnection; - private bool _disposed; + private Connection _innerConnection; + private bool _disposed; - private Connection InnerConnection - { - get + private Connection InnerConnection { - ThrowIfDisposed(); - return _innerConnection; + get + { + ThrowIfDisposed(); + return _innerConnection; + } } - } - - public AutorecoveringConnection(ConnectionConfig config, IEndpointResolver endpoints) - { - _config = config; - _endpoints = endpoints; - IFrameHandler fh = _endpoints.SelectOne(_config.FrameHandlerFactory); + public AutorecoveringConnection(ConnectionConfig config, IEndpointResolver endpoints) + { + _config = config; + _endpoints = endpoints; - _innerConnection = new Connection(_config, fh); + IFrameHandler fh = _endpoints.SelectOne(_config.FrameHandlerFactory); - Action onException = - (exception, context) => - _innerConnection.OnCallbackException(CallbackExceptionEventArgs.Build(exception, context)); - _recoverySucceededWrapper = new EventingWrapper("OnConnectionRecovery", onException); - _connectionRecoveryErrorWrapper = new EventingWrapper("OnConnectionRecoveryError", onException); - _consumerTagChangeAfterRecoveryWrapper = new EventingWrapper("OnConsumerRecovery", onException); - _queueNameChangeAfterRecoveryWrapper = new EventingWrapper("OnQueueRecovery", onException); + _innerConnection = new Connection(_config, fh); - ConnectionShutdown += HandleConnectionShutdown; - } + Action onException = + (exception, context) => + _innerConnection.OnCallbackException(CallbackExceptionEventArgs.Build(exception, context)); + _recoverySucceededWrapper = new EventingWrapper("OnConnectionRecovery", onException); + _connectionRecoveryErrorWrapper = new EventingWrapper("OnConnectionRecoveryError", onException); + _consumerTagChangeAfterRecoveryWrapper = new EventingWrapper("OnConsumerRecovery", onException); + _queueNameChangeAfterRecoveryWrapper = new EventingWrapper("OnQueueRecovery", onException); - public event EventHandler RecoverySucceeded - { - add => _recoverySucceededWrapper.AddHandler(value); - remove => _recoverySucceededWrapper.RemoveHandler(value); - } - private EventingWrapper _recoverySucceededWrapper; + ConnectionShutdown += HandleConnectionShutdown; + } - public event EventHandler ConnectionRecoveryError - { - add => _connectionRecoveryErrorWrapper.AddHandler(value); - remove => _connectionRecoveryErrorWrapper.RemoveHandler(value); - } - private EventingWrapper _connectionRecoveryErrorWrapper; + public event EventHandler RecoverySucceeded + { + add => _recoverySucceededWrapper.AddHandler(value); + remove => _recoverySucceededWrapper.RemoveHandler(value); + } + private EventingWrapper _recoverySucceededWrapper; - public event EventHandler CallbackException - { - add => InnerConnection.CallbackException += value; - remove => InnerConnection.CallbackException -= value; - } + public event EventHandler ConnectionRecoveryError + { + add => _connectionRecoveryErrorWrapper.AddHandler(value); + remove => _connectionRecoveryErrorWrapper.RemoveHandler(value); + } + private EventingWrapper _connectionRecoveryErrorWrapper; - public event EventHandler ConnectionBlocked - { - add => InnerConnection.ConnectionBlocked += value; - remove => InnerConnection.ConnectionBlocked -= value; - } + public event EventHandler CallbackException + { + add => InnerConnection.CallbackException += value; + remove => InnerConnection.CallbackException -= value; + } - public event EventHandler ConnectionShutdown - { - add => InnerConnection.ConnectionShutdown += value; - remove => InnerConnection.ConnectionShutdown -= value; - } + public event EventHandler ConnectionBlocked + { + add => InnerConnection.ConnectionBlocked += value; + remove => InnerConnection.ConnectionBlocked -= value; + } - public event EventHandler ConnectionUnblocked - { - add => InnerConnection.ConnectionUnblocked += value; - remove => InnerConnection.ConnectionUnblocked -= value; - } + public event EventHandler ConnectionShutdown + { + add => InnerConnection.ConnectionShutdown += value; + remove => InnerConnection.ConnectionShutdown -= value; + } - public event EventHandler ConsumerTagChangeAfterRecovery - { - add => _consumerTagChangeAfterRecoveryWrapper.AddHandler(value); - remove => _consumerTagChangeAfterRecoveryWrapper.RemoveHandler(value); - } - private EventingWrapper _consumerTagChangeAfterRecoveryWrapper; + public event EventHandler ConnectionUnblocked + { + add => InnerConnection.ConnectionUnblocked += value; + remove => InnerConnection.ConnectionUnblocked -= value; + } - public event EventHandler QueueNameChangeAfterRecovery - { - add => _queueNameChangeAfterRecoveryWrapper.AddHandler(value); - remove => _queueNameChangeAfterRecoveryWrapper.RemoveHandler(value); - } - private EventingWrapper _queueNameChangeAfterRecoveryWrapper; + public event EventHandler ConsumerTagChangeAfterRecovery + { + add => _consumerTagChangeAfterRecoveryWrapper.AddHandler(value); + remove => _consumerTagChangeAfterRecoveryWrapper.RemoveHandler(value); + } + private EventingWrapper _consumerTagChangeAfterRecoveryWrapper; - public string ClientProvidedName => _config.ClientProvidedName; + public event EventHandler QueueNameChangeAfterRecovery + { + add => _queueNameChangeAfterRecoveryWrapper.AddHandler(value); + remove => _queueNameChangeAfterRecoveryWrapper.RemoveHandler(value); + } + private EventingWrapper _queueNameChangeAfterRecoveryWrapper; - public ushort ChannelMax => InnerConnection.ChannelMax; + public string ClientProvidedName => _config.ClientProvidedName; - public IDictionary ClientProperties => InnerConnection.ClientProperties; + public ushort ChannelMax => InnerConnection.ChannelMax; - public ShutdownEventArgs CloseReason => InnerConnection.CloseReason; + public IDictionary ClientProperties => InnerConnection.ClientProperties; - public AmqpTcpEndpoint Endpoint => InnerConnection.Endpoint; + public ShutdownEventArgs CloseReason => InnerConnection.CloseReason; - public uint FrameMax => InnerConnection.FrameMax; + public AmqpTcpEndpoint Endpoint => InnerConnection.Endpoint; - public TimeSpan Heartbeat => InnerConnection.Heartbeat; + public uint FrameMax => InnerConnection.FrameMax; - public bool IsOpen => _innerConnection?.IsOpen ?? false; + public TimeSpan Heartbeat => InnerConnection.Heartbeat; - public int LocalPort => InnerConnection.LocalPort; + public bool IsOpen => _innerConnection?.IsOpen ?? false; - public int RemotePort => InnerConnection.RemotePort; + public int LocalPort => InnerConnection.LocalPort; - public IDictionary ServerProperties => InnerConnection.ServerProperties; + public int RemotePort => InnerConnection.RemotePort; - public IList ShutdownReport => InnerConnection.ShutdownReport; + public IDictionary ServerProperties => InnerConnection.ServerProperties; - public IProtocol Protocol => Endpoint.Protocol; + public IList ShutdownReport => InnerConnection.ShutdownReport; - public RecoveryAwareModel CreateNonRecoveringModel() - { - ISession session = InnerConnection.CreateSession(); - var result = new RecoveryAwareModel(_config, session); - result._Private_ChannelOpen(); - return result; - } + public IProtocol Protocol => Endpoint.Protocol; - public override string ToString() - => $"AutorecoveringConnection({InnerConnection.Id},{Endpoint},{GetHashCode()})"; + public RecoveryAwareModel CreateNonRecoveringModel() + { + ISession session = InnerConnection.CreateSession(); + var result = new RecoveryAwareModel(_config, session); + result._Private_ChannelOpen(); + return result; + } - internal IFrameHandler FrameHandler => InnerConnection.FrameHandler; + public override string ToString() + => $"AutorecoveringConnection({InnerConnection.Id},{Endpoint},{GetHashCode()})"; - internal string Password => _config.Password; + internal IFrameHandler FrameHandler => InnerConnection.FrameHandler; - ///API-side invocation of updating the secret. - public void UpdateSecret(string newSecret, string reason) - { - ThrowIfDisposed(); - EnsureIsOpen(); - _innerConnection.UpdateSecret(newSecret, reason); - _config.Password = newSecret; - } + internal string Password => _config.Password; - ///API-side invocation of connection.close with timeout. - public void Close(ushort reasonCode, string reasonText, TimeSpan timeout, bool abort) - { - ThrowIfDisposed(); - StopRecoveryLoop(); - if (_innerConnection.IsOpen) + ///API-side invocation of updating the secret. + public void UpdateSecret(string newSecret, string reason) { - _innerConnection.Close(reasonCode, reasonText, timeout, abort); + ThrowIfDisposed(); + EnsureIsOpen(); + _innerConnection.UpdateSecret(newSecret, reason); + _config.Password = newSecret; } - } - - public IModel CreateModel() - { - EnsureIsOpen(); - AutorecoveringModel m = new AutorecoveringModel(this, CreateNonRecoveringModel()); - RecordChannel(m); - return m; - } - public void Dispose() - { - if (_disposed) + ///API-side invocation of connection.close with timeout. + public void Close(ushort reasonCode, string reasonText, TimeSpan timeout, bool abort) { - return; + ThrowIfDisposed(); + StopRecoveryLoop(); + if (_innerConnection.IsOpen) + { + _innerConnection.Close(reasonCode, reasonText, timeout, abort); + } } - try + public IModel CreateModel() { - this.Abort(InternalConstants.DefaultConnectionAbortTimeout); + EnsureIsOpen(); + AutorecoveringModel m = new AutorecoveringModel(this, CreateNonRecoveringModel()); + RecordChannel(m); + return m; } - catch (Exception) - { - // TODO: log - } - finally + + public void Dispose() { - _models.Clear(); - _innerConnection = null; - _disposed = true; + if (_disposed) + { + return; + } + + try + { + this.Abort(InternalConstants.DefaultConnectionAbortTimeout); + } + catch (Exception) + { + // TODO: log + } + finally + { + _models.Clear(); + _innerConnection = null; + _disposed = true; + } } - } - private void EnsureIsOpen() - => InnerConnection.EnsureIsOpen(); + private void EnsureIsOpen() + => InnerConnection.EnsureIsOpen(); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void ThrowIfDisposed() - { - if (_disposed) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void ThrowIfDisposed() { - ThrowDisposed(); - } + if (_disposed) + { + ThrowDisposed(); + } - static void ThrowDisposed() => throw new ObjectDisposedException(typeof(AutorecoveringConnection).FullName); + static void ThrowDisposed() => throw new ObjectDisposedException(typeof(AutorecoveringConnection).FullName); + } } } diff --git a/projects/RabbitMQ.Client/client/impl/AutorecoveringModel.cs b/projects/RabbitMQ.Client/client/impl/AutorecoveringModel.cs index b477d03130..601d27d469 100644 --- a/projects/RabbitMQ.Client/client/impl/AutorecoveringModel.cs +++ b/projects/RabbitMQ.Client/client/impl/AutorecoveringModel.cs @@ -38,389 +38,390 @@ using RabbitMQ.Client.Events; using RabbitMQ.Client.Framing.Impl; -namespace RabbitMQ.Client.Impl; - -internal sealed class AutorecoveringModel : IModel, IRecoverable +namespace RabbitMQ.Client.Impl { - private AutorecoveringConnection _connection; - private RecoveryAwareModel _innerChannel; - private bool _disposed; + internal sealed class AutorecoveringModel : IModel, IRecoverable + { + private AutorecoveringConnection _connection; + private RecoveryAwareModel _innerChannel; + private bool _disposed; - private ushort _prefetchCountConsumer; - private ushort _prefetchCountGlobal; - private bool _usesPublisherConfirms; - private bool _usesTransactions; + private ushort _prefetchCountConsumer; + private ushort _prefetchCountGlobal; + private bool _usesPublisherConfirms; + private bool _usesTransactions; - internal IConsumerDispatcher ConsumerDispatcher => InnerChannel.ConsumerDispatcher; + internal IConsumerDispatcher ConsumerDispatcher => InnerChannel.ConsumerDispatcher; - internal RecoveryAwareModel InnerChannel - { - get + internal RecoveryAwareModel InnerChannel { - ThrowIfDisposed(); - return _innerChannel; + get + { + ThrowIfDisposed(); + return _innerChannel; + } } - } - public TimeSpan ContinuationTimeout - { - get => InnerChannel.ContinuationTimeout; - set => InnerChannel.ContinuationTimeout = value; - } - - public AutorecoveringModel(AutorecoveringConnection conn, RecoveryAwareModel innerChannel) - { - _connection = conn; - _innerChannel = innerChannel; - } - - public event EventHandler BasicAcks - { - add => InnerChannel.BasicAcks += value; - remove => InnerChannel.BasicAcks -= value; - } + public TimeSpan ContinuationTimeout + { + get => InnerChannel.ContinuationTimeout; + set => InnerChannel.ContinuationTimeout = value; + } - public event EventHandler BasicNacks - { - add => InnerChannel.BasicNacks += value; - remove => InnerChannel.BasicNacks -= value; - } + public AutorecoveringModel(AutorecoveringConnection conn, RecoveryAwareModel innerChannel) + { + _connection = conn; + _innerChannel = innerChannel; + } - public event EventHandler BasicRecoverOk - { - add => InnerChannel.BasicRecoverOk += value; - remove => InnerChannel.BasicRecoverOk -= value; - } + public event EventHandler BasicAcks + { + add => InnerChannel.BasicAcks += value; + remove => InnerChannel.BasicAcks -= value; + } - public event EventHandler BasicReturn - { - add => InnerChannel.BasicReturn += value; - remove => InnerChannel.BasicReturn -= value; - } + public event EventHandler BasicNacks + { + add => InnerChannel.BasicNacks += value; + remove => InnerChannel.BasicNacks -= value; + } - public event EventHandler CallbackException - { - add => InnerChannel.CallbackException += value; - remove => InnerChannel.CallbackException -= value; - } + public event EventHandler BasicRecoverOk + { + add => InnerChannel.BasicRecoverOk += value; + remove => InnerChannel.BasicRecoverOk -= value; + } - public event EventHandler FlowControl - { - add { InnerChannel.FlowControl += value; } - remove { InnerChannel.FlowControl -= value; } - } + public event EventHandler BasicReturn + { + add => InnerChannel.BasicReturn += value; + remove => InnerChannel.BasicReturn -= value; + } - public event EventHandler ModelShutdown - { - add => InnerChannel.ModelShutdown += value; - remove => InnerChannel.ModelShutdown -= value; - } + public event EventHandler CallbackException + { + add => InnerChannel.CallbackException += value; + remove => InnerChannel.CallbackException -= value; + } - public event EventHandler Recovery - { - add { InnerChannel.Recovery += value; } - remove { InnerChannel.Recovery -= value; } - } + public event EventHandler FlowControl + { + add { InnerChannel.FlowControl += value; } + remove { InnerChannel.FlowControl -= value; } + } - public int ChannelNumber => InnerChannel.ChannelNumber; + public event EventHandler ModelShutdown + { + add => InnerChannel.ModelShutdown += value; + remove => InnerChannel.ModelShutdown -= value; + } - public ShutdownEventArgs CloseReason => InnerChannel.CloseReason; + public event EventHandler Recovery + { + add { InnerChannel.Recovery += value; } + remove { InnerChannel.Recovery -= value; } + } - public IBasicConsumer DefaultConsumer - { - get => InnerChannel.DefaultConsumer; - set => InnerChannel.DefaultConsumer = value; - } + public int ChannelNumber => InnerChannel.ChannelNumber; - public bool IsClosed => !IsOpen; + public ShutdownEventArgs CloseReason => InnerChannel.CloseReason; - public bool IsOpen => _innerChannel != null && _innerChannel.IsOpen; + public IBasicConsumer DefaultConsumer + { + get => InnerChannel.DefaultConsumer; + set => InnerChannel.DefaultConsumer = value; + } - public ulong NextPublishSeqNo => InnerChannel.NextPublishSeqNo; + public bool IsClosed => !IsOpen; - internal void AutomaticallyRecover(AutorecoveringConnection conn, bool recoverConsumers) - { - ThrowIfDisposed(); - _connection = conn; + public bool IsOpen => _innerChannel != null && _innerChannel.IsOpen; - var newChannel = conn.CreateNonRecoveringModel(); - newChannel.TakeOver(_innerChannel); + public ulong NextPublishSeqNo => InnerChannel.NextPublishSeqNo; - if (_prefetchCountConsumer != 0) + internal void AutomaticallyRecover(AutorecoveringConnection conn, bool recoverConsumers) { - newChannel.BasicQos(0, _prefetchCountConsumer, false); + ThrowIfDisposed(); + _connection = conn; + + var newChannel = conn.CreateNonRecoveringModel(); + newChannel.TakeOver(_innerChannel); + + if (_prefetchCountConsumer != 0) + { + newChannel.BasicQos(0, _prefetchCountConsumer, false); + } + + if (_prefetchCountGlobal != 0) + { + newChannel.BasicQos(0, _prefetchCountGlobal, true); + } + + if (_usesPublisherConfirms) + { + newChannel.ConfirmSelect(); + } + + if (_usesTransactions) + { + newChannel.TxSelect(); + } + + /* + * https://github.com/rabbitmq/rabbitmq-dotnet-client/issues/1140 + * If this assignment is not done before recovering consumers, there is a good + * chance that an invalid Model will be used to handle a basic.deliver frame, + * with the resulting basic.ack never getting sent out. + */ + _innerChannel = newChannel; + + if (recoverConsumers) + { + _connection.RecoverConsumers(this, newChannel); + } + + _innerChannel.RunRecoveryEventHandlers(this); } - if (_prefetchCountGlobal != 0) + public void Close(ushort replyCode, string replyText, bool abort) { - newChannel.BasicQos(0, _prefetchCountGlobal, true); + ThrowIfDisposed(); + try + { + _innerChannel.Close(replyCode, replyText, abort); + } + finally + { + _connection.DeleteRecordedChannel(this); + } } - if (_usesPublisherConfirms) - { - newChannel.ConfirmSelect(); - } + public override string ToString() + => InnerChannel.ToString(); - if (_usesTransactions) + public void Dispose() { - newChannel.TxSelect(); - } + if (_disposed) + { + return; + } - /* - * https://github.com/rabbitmq/rabbitmq-dotnet-client/issues/1140 - * If this assignment is not done before recovering consumers, there is a good - * chance that an invalid Model will be used to handle a basic.deliver frame, - * with the resulting basic.ack never getting sent out. - */ - _innerChannel = newChannel; + this.Abort(); - if (recoverConsumers) - { - _connection.RecoverConsumers(this, newChannel); + _connection = null; + _innerChannel = null; + _disposed = true; } - _innerChannel.RunRecoveryEventHandlers(this); - } + public void BasicAck(ulong deliveryTag, bool multiple) + => InnerChannel.BasicAck(deliveryTag, multiple); - public void Close(ushort replyCode, string replyText, bool abort) - { - ThrowIfDisposed(); - try + public void BasicCancel(string consumerTag) { - _innerChannel.Close(replyCode, replyText, abort); + ThrowIfDisposed(); + _connection.DeleteRecordedConsumer(consumerTag); + _innerChannel.BasicCancel(consumerTag); } - finally + + public void BasicCancelNoWait(string consumerTag) { - _connection.DeleteRecordedChannel(this); + ThrowIfDisposed(); + _connection.DeleteRecordedConsumer(consumerTag); + _innerChannel.BasicCancelNoWait(consumerTag); } - } - public override string ToString() - => InnerChannel.ToString(); - - public void Dispose() - { - if (_disposed) + public string BasicConsume( + string queue, + bool autoAck, + string consumerTag, + bool noLocal, + bool exclusive, + IDictionary arguments, + IBasicConsumer consumer) { - return; + string result = InnerChannel.BasicConsume(queue, autoAck, consumerTag, noLocal, exclusive, arguments, consumer); + _connection.RecordConsumer(new RecordedConsumer(this, consumer, queue, autoAck, result, exclusive, arguments)); + return result; } - this.Abort(); + public BasicGetResult BasicGet(string queue, bool autoAck) + => InnerChannel.BasicGet(queue, autoAck); - _connection = null; - _innerChannel = null; - _disposed = true; - } + public void BasicNack(ulong deliveryTag, bool multiple, bool requeue) + => InnerChannel.BasicNack(deliveryTag, multiple, requeue); - public void BasicAck(ulong deliveryTag, bool multiple) - => InnerChannel.BasicAck(deliveryTag, multiple); + public void BasicPublish(string exchange, string routingKey, ref TProperties basicProperties, ReadOnlyMemory body, bool mandatory) + where TProperties : IReadOnlyBasicProperties, IAmqpHeader + => InnerChannel.BasicPublish(exchange, routingKey, ref basicProperties, body, mandatory); - public void BasicCancel(string consumerTag) - { - ThrowIfDisposed(); - _connection.DeleteRecordedConsumer(consumerTag); - _innerChannel.BasicCancel(consumerTag); - } - - public void BasicCancelNoWait(string consumerTag) - { - ThrowIfDisposed(); - _connection.DeleteRecordedConsumer(consumerTag); - _innerChannel.BasicCancelNoWait(consumerTag); - } - - public string BasicConsume( - string queue, - bool autoAck, - string consumerTag, - bool noLocal, - bool exclusive, - IDictionary arguments, - IBasicConsumer consumer) - { - string result = InnerChannel.BasicConsume(queue, autoAck, consumerTag, noLocal, exclusive, arguments, consumer); - _connection.RecordConsumer(new RecordedConsumer(this, consumer, queue, autoAck, result, exclusive, arguments)); - return result; - } + public void BasicPublish(CachedString exchange, CachedString routingKey, ref TProperties basicProperties, ReadOnlyMemory body, bool mandatory) + where TProperties : IReadOnlyBasicProperties, IAmqpHeader + => InnerChannel.BasicPublish(exchange, routingKey, ref basicProperties, body, mandatory); - public BasicGetResult BasicGet(string queue, bool autoAck) - => InnerChannel.BasicGet(queue, autoAck); + public void BasicQos(uint prefetchSize, ushort prefetchCount, bool global) + { + ThrowIfDisposed(); + if (global) + { + _prefetchCountGlobal = prefetchCount; + } + else + { + _prefetchCountConsumer = prefetchCount; + } + _innerChannel.BasicQos(prefetchSize, prefetchCount, global); + } - public void BasicNack(ulong deliveryTag, bool multiple, bool requeue) - => InnerChannel.BasicNack(deliveryTag, multiple, requeue); + public void BasicRecover(bool requeue) + => InnerChannel.BasicRecover(requeue); - public void BasicPublish(string exchange, string routingKey, ref TProperties basicProperties, ReadOnlyMemory body, bool mandatory) - where TProperties : IReadOnlyBasicProperties, IAmqpHeader - => InnerChannel.BasicPublish(exchange, routingKey, ref basicProperties, body, mandatory); + public void BasicRecoverAsync(bool requeue) + => InnerChannel.BasicRecoverAsync(requeue); - public void BasicPublish(CachedString exchange, CachedString routingKey, ref TProperties basicProperties, ReadOnlyMemory body, bool mandatory) - where TProperties : IReadOnlyBasicProperties, IAmqpHeader - => InnerChannel.BasicPublish(exchange, routingKey, ref basicProperties, body, mandatory); + public void BasicReject(ulong deliveryTag, bool requeue) + => InnerChannel.BasicReject(deliveryTag, requeue); - public void BasicQos(uint prefetchSize, ushort prefetchCount, bool global) - { - ThrowIfDisposed(); - if (global) + public void ConfirmSelect() { - _prefetchCountGlobal = prefetchCount; + InnerChannel.ConfirmSelect(); + _usesPublisherConfirms = true; } - else + + public void ExchangeBind(string destination, string source, string routingKey, IDictionary arguments) { - _prefetchCountConsumer = prefetchCount; + ThrowIfDisposed(); + _connection.RecordBinding(new RecordedBinding(false, destination, source, routingKey, arguments)); + _innerChannel.ExchangeBind(destination, source, routingKey, arguments); } - _innerChannel.BasicQos(prefetchSize, prefetchCount, global); - } - - public void BasicRecover(bool requeue) - => InnerChannel.BasicRecover(requeue); - public void BasicRecoverAsync(bool requeue) - => InnerChannel.BasicRecoverAsync(requeue); + public void ExchangeBindNoWait(string destination, string source, string routingKey, IDictionary arguments) + => InnerChannel.ExchangeBindNoWait(destination, source, routingKey, arguments); - public void BasicReject(ulong deliveryTag, bool requeue) - => InnerChannel.BasicReject(deliveryTag, requeue); - - public void ConfirmSelect() - { - InnerChannel.ConfirmSelect(); - _usesPublisherConfirms = true; - } - - public void ExchangeBind(string destination, string source, string routingKey, IDictionary arguments) - { - ThrowIfDisposed(); - _connection.RecordBinding(new RecordedBinding(false, destination, source, routingKey, arguments)); - _innerChannel.ExchangeBind(destination, source, routingKey, arguments); - } - - public void ExchangeBindNoWait(string destination, string source, string routingKey, IDictionary arguments) - => InnerChannel.ExchangeBindNoWait(destination, source, routingKey, arguments); - - public void ExchangeDeclare(string exchange, string type, bool durable, bool autoDelete, IDictionary arguments) - { - ThrowIfDisposed(); - _innerChannel.ExchangeDeclare(exchange, type, durable, autoDelete, arguments); - _connection.RecordExchange(new RecordedExchange(exchange, type, durable, autoDelete, arguments)); - } + public void ExchangeDeclare(string exchange, string type, bool durable, bool autoDelete, IDictionary arguments) + { + ThrowIfDisposed(); + _innerChannel.ExchangeDeclare(exchange, type, durable, autoDelete, arguments); + _connection.RecordExchange(new RecordedExchange(exchange, type, durable, autoDelete, arguments)); + } - public void ExchangeDeclareNoWait(string exchange, string type, bool durable, bool autoDelete, IDictionary arguments) - { - ThrowIfDisposed(); - _innerChannel.ExchangeDeclareNoWait(exchange, type, durable, autoDelete, arguments); - _connection.RecordExchange(new RecordedExchange(exchange, type, durable, autoDelete, arguments)); - } + public void ExchangeDeclareNoWait(string exchange, string type, bool durable, bool autoDelete, IDictionary arguments) + { + ThrowIfDisposed(); + _innerChannel.ExchangeDeclareNoWait(exchange, type, durable, autoDelete, arguments); + _connection.RecordExchange(new RecordedExchange(exchange, type, durable, autoDelete, arguments)); + } - public void ExchangeDeclarePassive(string exchange) - => InnerChannel.ExchangeDeclarePassive(exchange); + public void ExchangeDeclarePassive(string exchange) + => InnerChannel.ExchangeDeclarePassive(exchange); - public void ExchangeDelete(string exchange, bool ifUnused) - { - InnerChannel.ExchangeDelete(exchange, ifUnused); - _connection.DeleteRecordedExchange(exchange); - } + public void ExchangeDelete(string exchange, bool ifUnused) + { + InnerChannel.ExchangeDelete(exchange, ifUnused); + _connection.DeleteRecordedExchange(exchange); + } - public void ExchangeDeleteNoWait(string exchange, bool ifUnused) - { - InnerChannel.ExchangeDeleteNoWait(exchange, ifUnused); - _connection.DeleteRecordedExchange(exchange); - } + public void ExchangeDeleteNoWait(string exchange, bool ifUnused) + { + InnerChannel.ExchangeDeleteNoWait(exchange, ifUnused); + _connection.DeleteRecordedExchange(exchange); + } - public void ExchangeUnbind(string destination, string source, string routingKey, IDictionary arguments) - { - ThrowIfDisposed(); - _connection.DeleteRecordedBinding(new RecordedBinding(false, destination, source, routingKey, arguments)); - _innerChannel.ExchangeUnbind(destination, source, routingKey, arguments); - _connection.DeleteAutoDeleteExchange(source); - } + public void ExchangeUnbind(string destination, string source, string routingKey, IDictionary arguments) + { + ThrowIfDisposed(); + _connection.DeleteRecordedBinding(new RecordedBinding(false, destination, source, routingKey, arguments)); + _innerChannel.ExchangeUnbind(destination, source, routingKey, arguments); + _connection.DeleteAutoDeleteExchange(source); + } - public void ExchangeUnbindNoWait(string destination, string source, string routingKey, IDictionary arguments) - => InnerChannel.ExchangeUnbind(destination, source, routingKey, arguments); + public void ExchangeUnbindNoWait(string destination, string source, string routingKey, IDictionary arguments) + => InnerChannel.ExchangeUnbind(destination, source, routingKey, arguments); - public void QueueBind(string queue, string exchange, string routingKey, IDictionary arguments) - { - ThrowIfDisposed(); - _connection.RecordBinding(new RecordedBinding(true, queue, exchange, routingKey, arguments)); - _innerChannel.QueueBind(queue, exchange, routingKey, arguments); - } + public void QueueBind(string queue, string exchange, string routingKey, IDictionary arguments) + { + ThrowIfDisposed(); + _connection.RecordBinding(new RecordedBinding(true, queue, exchange, routingKey, arguments)); + _innerChannel.QueueBind(queue, exchange, routingKey, arguments); + } - public void QueueBindNoWait(string queue, string exchange, string routingKey, IDictionary arguments) - => InnerChannel.QueueBind(queue, exchange, routingKey, arguments); + public void QueueBindNoWait(string queue, string exchange, string routingKey, IDictionary arguments) + => InnerChannel.QueueBind(queue, exchange, routingKey, arguments); - public QueueDeclareOk QueueDeclare(string queue, bool durable, bool exclusive, bool autoDelete, IDictionary arguments) - { - ThrowIfDisposed(); - QueueDeclareOk result = _innerChannel.QueueDeclare(queue, durable, exclusive, autoDelete, arguments); - _connection.RecordQueue(new RecordedQueue(result.QueueName, queue.Length == 0, durable, exclusive, autoDelete, arguments)); - return result; - } + public QueueDeclareOk QueueDeclare(string queue, bool durable, bool exclusive, bool autoDelete, IDictionary arguments) + { + ThrowIfDisposed(); + QueueDeclareOk result = _innerChannel.QueueDeclare(queue, durable, exclusive, autoDelete, arguments); + _connection.RecordQueue(new RecordedQueue(result.QueueName, queue.Length == 0, durable, exclusive, autoDelete, arguments)); + return result; + } - public void QueueDeclareNoWait(string queue, bool durable, bool exclusive, bool autoDelete, IDictionary arguments) - { - ThrowIfDisposed(); - _innerChannel.QueueDeclareNoWait(queue, durable, exclusive, autoDelete, arguments); - _connection.RecordQueue(new RecordedQueue(queue, queue.Length == 0, durable, exclusive, autoDelete, arguments)); - } + public void QueueDeclareNoWait(string queue, bool durable, bool exclusive, bool autoDelete, IDictionary arguments) + { + ThrowIfDisposed(); + _innerChannel.QueueDeclareNoWait(queue, durable, exclusive, autoDelete, arguments); + _connection.RecordQueue(new RecordedQueue(queue, queue.Length == 0, durable, exclusive, autoDelete, arguments)); + } - public QueueDeclareOk QueueDeclarePassive(string queue) - => InnerChannel.QueueDeclarePassive(queue); + public QueueDeclareOk QueueDeclarePassive(string queue) + => InnerChannel.QueueDeclarePassive(queue); - public uint MessageCount(string queue) - => InnerChannel.MessageCount(queue); + public uint MessageCount(string queue) + => InnerChannel.MessageCount(queue); - public uint ConsumerCount(string queue) - => InnerChannel.ConsumerCount(queue); + public uint ConsumerCount(string queue) + => InnerChannel.ConsumerCount(queue); - public uint QueueDelete(string queue, bool ifUnused, bool ifEmpty) - { - ThrowIfDisposed(); - uint result = _innerChannel.QueueDelete(queue, ifUnused, ifEmpty); - _connection.DeleteRecordedQueue(queue); - return result; - } + public uint QueueDelete(string queue, bool ifUnused, bool ifEmpty) + { + ThrowIfDisposed(); + uint result = _innerChannel.QueueDelete(queue, ifUnused, ifEmpty); + _connection.DeleteRecordedQueue(queue); + return result; + } - public void QueueDeleteNoWait(string queue, bool ifUnused, bool ifEmpty) - { - InnerChannel.QueueDeleteNoWait(queue, ifUnused, ifEmpty); - _connection.DeleteRecordedQueue(queue); - } + public void QueueDeleteNoWait(string queue, bool ifUnused, bool ifEmpty) + { + InnerChannel.QueueDeleteNoWait(queue, ifUnused, ifEmpty); + _connection.DeleteRecordedQueue(queue); + } - public uint QueuePurge(string queue) - => InnerChannel.QueuePurge(queue); + public uint QueuePurge(string queue) + => InnerChannel.QueuePurge(queue); - public void QueueUnbind(string queue, string exchange, string routingKey, IDictionary arguments) - { - ThrowIfDisposed(); - _connection.DeleteRecordedBinding(new RecordedBinding(true, queue, exchange, routingKey, arguments)); - _innerChannel.QueueUnbind(queue, exchange, routingKey, arguments); - _connection.DeleteAutoDeleteExchange(exchange); - } + public void QueueUnbind(string queue, string exchange, string routingKey, IDictionary arguments) + { + ThrowIfDisposed(); + _connection.DeleteRecordedBinding(new RecordedBinding(true, queue, exchange, routingKey, arguments)); + _innerChannel.QueueUnbind(queue, exchange, routingKey, arguments); + _connection.DeleteAutoDeleteExchange(exchange); + } - public void TxCommit() - => InnerChannel.TxCommit(); + public void TxCommit() + => InnerChannel.TxCommit(); - public void TxRollback() - => InnerChannel.TxRollback(); + public void TxRollback() + => InnerChannel.TxRollback(); - public void TxSelect() - { - InnerChannel.TxSelect(); - _usesTransactions = true; - } + public void TxSelect() + { + InnerChannel.TxSelect(); + _usesTransactions = true; + } - public Task WaitForConfirmsAsync(CancellationToken token = default) - => InnerChannel.WaitForConfirmsAsync(token); + public Task WaitForConfirmsAsync(CancellationToken token = default) + => InnerChannel.WaitForConfirmsAsync(token); - public Task WaitForConfirmsOrDieAsync(CancellationToken token = default) - => InnerChannel.WaitForConfirmsOrDieAsync(token); + public Task WaitForConfirmsOrDieAsync(CancellationToken token = default) + => InnerChannel.WaitForConfirmsOrDieAsync(token); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void ThrowIfDisposed() - { - if (_disposed) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void ThrowIfDisposed() { - ThrowDisposed(); - } + if (_disposed) + { + ThrowDisposed(); + } - static void ThrowDisposed() => throw new ObjectDisposedException(typeof(AutorecoveringModel).FullName); + static void ThrowDisposed() => throw new ObjectDisposedException(typeof(AutorecoveringModel).FullName); + } } } diff --git a/projects/RabbitMQ.Client/client/impl/CommandAssembler.cs b/projects/RabbitMQ.Client/client/impl/CommandAssembler.cs index 24d14869da..9edf3ceb1b 100644 --- a/projects/RabbitMQ.Client/client/impl/CommandAssembler.cs +++ b/projects/RabbitMQ.Client/client/impl/CommandAssembler.cs @@ -37,171 +37,172 @@ using RabbitMQ.Client.Logging; using RabbitMQ.Util; -namespace RabbitMQ.Client.Impl; - -#nullable enable -internal sealed class CommandAssembler +namespace RabbitMQ.Client.Impl { - private const int MaxArrayOfBytesSize = 2_147_483_591; - - private ProtocolCommandId _commandId; - private ReadOnlyMemory _methodBytes; - private byte[]? _rentedMethodArray; - private ReadOnlyMemory _headerBytes; - private byte[]? _rentedHeaderArray; - private ReadOnlyMemory _bodyBytes; - private byte[]? _rentedBodyArray; - private int _remainingBodyBytes; - private int _offset; - private AssemblyState _state; - - public CommandAssembler() - { - Reset(); - } - - private void Reset() - { - _commandId = default; - _methodBytes = ReadOnlyMemory.Empty; - _rentedMethodArray = null; - _headerBytes = ReadOnlyMemory.Empty; - _rentedHeaderArray = null; - _bodyBytes = ReadOnlyMemory.Empty; - _rentedBodyArray = null; - _remainingBodyBytes = 0; - _offset = 0; - _state = AssemblyState.ExpectingMethod; - } - - public bool HandleFrame(in InboundFrame frame, out IncomingCommand command) +#nullable enable + internal sealed class CommandAssembler { - bool shallReturn = true; - switch (_state) + private const int MaxArrayOfBytesSize = 2_147_483_591; + + private ProtocolCommandId _commandId; + private ReadOnlyMemory _methodBytes; + private byte[]? _rentedMethodArray; + private ReadOnlyMemory _headerBytes; + private byte[]? _rentedHeaderArray; + private ReadOnlyMemory _bodyBytes; + private byte[]? _rentedBodyArray; + private int _remainingBodyBytes; + private int _offset; + private AssemblyState _state; + + public CommandAssembler() { - case AssemblyState.ExpectingMethod: - ParseMethodFrame(in frame); - shallReturn = false; - break; - case AssemblyState.ExpectingContentHeader: - shallReturn = ParseHeaderFrame(in frame); - break; - case AssemblyState.ExpectingContentBody: - shallReturn = ParseBodyFrame(in frame); - break; + Reset(); } - if (_state != AssemblyState.Complete) + private void Reset() { - command = IncomingCommand.Empty; - return shallReturn; + _commandId = default; + _methodBytes = ReadOnlyMemory.Empty; + _rentedMethodArray = null; + _headerBytes = ReadOnlyMemory.Empty; + _rentedHeaderArray = null; + _bodyBytes = ReadOnlyMemory.Empty; + _rentedBodyArray = null; + _remainingBodyBytes = 0; + _offset = 0; + _state = AssemblyState.ExpectingMethod; } - RabbitMqClientEventSource.Log.CommandReceived(); - command = new IncomingCommand(_commandId, _methodBytes, _rentedMethodArray, _headerBytes, _rentedHeaderArray, _bodyBytes, _rentedBodyArray); - Reset(); - return shallReturn; - } - - private void ParseMethodFrame(in InboundFrame frame) - { - if (frame.Type != FrameType.FrameMethod) + public bool HandleFrame(in InboundFrame frame, out IncomingCommand command) { - throw new UnexpectedFrameException(frame.Type); - } + bool shallReturn = true; + switch (_state) + { + case AssemblyState.ExpectingMethod: + ParseMethodFrame(in frame); + shallReturn = false; + break; + case AssemblyState.ExpectingContentHeader: + shallReturn = ParseHeaderFrame(in frame); + break; + case AssemblyState.ExpectingContentBody: + shallReturn = ParseBodyFrame(in frame); + break; + } - _rentedMethodArray = frame.TakeoverPayload(); - _commandId = (ProtocolCommandId)NetworkOrderDeserializer.ReadUInt32(frame.Payload.Span); - _methodBytes = frame.Payload.Slice(4); + if (_state != AssemblyState.Complete) + { + command = IncomingCommand.Empty; + return shallReturn; + } - switch (_commandId) - { - // Commands with payload - case ProtocolCommandId.BasicGetOk: - case ProtocolCommandId.BasicDeliver: - case ProtocolCommandId.BasicReturn: - _state = AssemblyState.ExpectingContentHeader; - break; - default: - _state = AssemblyState.Complete; - break; + RabbitMqClientEventSource.Log.CommandReceived(); + command = new IncomingCommand(_commandId, _methodBytes, _rentedMethodArray, _headerBytes, _rentedHeaderArray, _bodyBytes, _rentedBodyArray); + Reset(); + return shallReturn; } - } - private bool ParseHeaderFrame(in InboundFrame frame) - { - if (frame.Type != FrameType.FrameHeader) + private void ParseMethodFrame(in InboundFrame frame) { - throw new UnexpectedFrameException(frame.Type); - } + if (frame.Type != FrameType.FrameMethod) + { + throw new UnexpectedFrameException(frame.Type); + } - ReadOnlySpan span = frame.Payload.Span; - var classId = NetworkOrderDeserializer.ReadUInt16(span); - if (classId != ClassConstants.Basic) - { - throw new UnknownClassOrMethodException(classId, 0); + _rentedMethodArray = frame.TakeoverPayload(); + _commandId = (ProtocolCommandId)NetworkOrderDeserializer.ReadUInt32(frame.Payload.Span); + _methodBytes = frame.Payload.Slice(4); + + switch (_commandId) + { + // Commands with payload + case ProtocolCommandId.BasicGetOk: + case ProtocolCommandId.BasicDeliver: + case ProtocolCommandId.BasicReturn: + _state = AssemblyState.ExpectingContentHeader; + break; + default: + _state = AssemblyState.Complete; + break; + } } - ulong totalBodyBytes = NetworkOrderDeserializer.ReadUInt64(span.Slice(4)); - if (totalBodyBytes > MaxArrayOfBytesSize) + private bool ParseHeaderFrame(in InboundFrame frame) { - throw new UnexpectedFrameException(frame.Type); - } - _rentedHeaderArray = totalBodyBytes != 0 ? frame.TakeoverPayload() : Array.Empty(); + if (frame.Type != FrameType.FrameHeader) + { + throw new UnexpectedFrameException(frame.Type); + } - _headerBytes = frame.Payload; + ReadOnlySpan span = frame.Payload.Span; + var classId = NetworkOrderDeserializer.ReadUInt16(span); + if (classId != ClassConstants.Basic) + { + throw new UnknownClassOrMethodException(classId, 0); + } - _remainingBodyBytes = (int)totalBodyBytes; - UpdateContentBodyState(); - return _rentedHeaderArray.Length == 0; - } + ulong totalBodyBytes = NetworkOrderDeserializer.ReadUInt64(span.Slice(4)); + if (totalBodyBytes > MaxArrayOfBytesSize) + { + throw new UnexpectedFrameException(frame.Type); + } + _rentedHeaderArray = totalBodyBytes != 0 ? frame.TakeoverPayload() : Array.Empty(); - private bool ParseBodyFrame(in InboundFrame frame) - { - if (frame.Type != FrameType.FrameBody) - { - throw new UnexpectedFrameException(frame.Type); - } + _headerBytes = frame.Payload; - int payloadLength = frame.Payload.Length; - if (payloadLength > _remainingBodyBytes) - { - throw new MalformedFrameException($"Overlong content body received - {_remainingBodyBytes} bytes remaining, {payloadLength} bytes received"); + _remainingBodyBytes = (int)totalBodyBytes; + UpdateContentBodyState(); + return _rentedHeaderArray.Length == 0; } - if (_rentedBodyArray is null) + private bool ParseBodyFrame(in InboundFrame frame) { - // check for single frame payload for an early exit - if (payloadLength == _remainingBodyBytes) + if (frame.Type != FrameType.FrameBody) { - _rentedBodyArray = frame.TakeoverPayload(); - _bodyBytes = frame.Payload; - _state = AssemblyState.Complete; - return false; + throw new UnexpectedFrameException(frame.Type); } - // Is returned by IncomingCommand.ReturnPayload in Session.HandleFrame - _rentedBodyArray = ArrayPool.Shared.Rent(_remainingBodyBytes); - _bodyBytes = new ReadOnlyMemory(_rentedBodyArray, 0, _remainingBodyBytes); - } + int payloadLength = frame.Payload.Length; + if (payloadLength > _remainingBodyBytes) + { + throw new MalformedFrameException($"Overlong content body received - {_remainingBodyBytes} bytes remaining, {payloadLength} bytes received"); + } - frame.Payload.Span.CopyTo(_rentedBodyArray.AsSpan(_offset)); - _remainingBodyBytes -= payloadLength; - _offset += payloadLength; - UpdateContentBodyState(); - return true; - } + if (_rentedBodyArray is null) + { + // check for single frame payload for an early exit + if (payloadLength == _remainingBodyBytes) + { + _rentedBodyArray = frame.TakeoverPayload(); + _bodyBytes = frame.Payload; + _state = AssemblyState.Complete; + return false; + } + + // Is returned by IncomingCommand.ReturnPayload in Session.HandleFrame + _rentedBodyArray = ArrayPool.Shared.Rent(_remainingBodyBytes); + _bodyBytes = new ReadOnlyMemory(_rentedBodyArray, 0, _remainingBodyBytes); + } - private void UpdateContentBodyState() - { - _state = _remainingBodyBytes > 0 ? AssemblyState.ExpectingContentBody : AssemblyState.Complete; - } + frame.Payload.Span.CopyTo(_rentedBodyArray.AsSpan(_offset)); + _remainingBodyBytes -= payloadLength; + _offset += payloadLength; + UpdateContentBodyState(); + return true; + } - private enum AssemblyState - { - ExpectingMethod, - ExpectingContentHeader, - ExpectingContentBody, - Complete + private void UpdateContentBodyState() + { + _state = _remainingBodyBytes > 0 ? AssemblyState.ExpectingContentBody : AssemblyState.Complete; + } + + private enum AssemblyState + { + ExpectingMethod, + ExpectingContentHeader, + ExpectingContentBody, + Complete + } } } diff --git a/projects/RabbitMQ.Client/client/impl/Connection.Commands.cs b/projects/RabbitMQ.Client/client/impl/Connection.Commands.cs index f945cad79d..7c53fe579b 100644 --- a/projects/RabbitMQ.Client/client/impl/Connection.Commands.cs +++ b/projects/RabbitMQ.Client/client/impl/Connection.Commands.cs @@ -38,151 +38,152 @@ using RabbitMQ.Client.Logging; using RabbitMQ.Util; -namespace RabbitMQ.Client.Framing.Impl; - -#nullable enable -internal sealed partial class Connection +namespace RabbitMQ.Client.Framing.Impl { - public void UpdateSecret(string newSecret, string reason) - { - _model0.UpdateSecret(newSecret, reason); - } - - internal void NotifyReceivedCloseOk() - { - TerminateMainloop(); - _closed = true; - } - - internal void HandleConnectionBlocked(string reason) +#nullable enable + internal sealed partial class Connection { - if (!_connectionBlockedWrapper.IsEmpty) + public void UpdateSecret(string newSecret, string reason) { - _connectionBlockedWrapper.Invoke(this, new ConnectionBlockedEventArgs(reason)); + _model0.UpdateSecret(newSecret, reason); } - } - internal void HandleConnectionUnblocked() - { - if (!_connectionUnblockedWrapper.IsEmpty) + internal void NotifyReceivedCloseOk() { - _connectionUnblockedWrapper.Invoke(this, EventArgs.Empty); + TerminateMainloop(); + _closed = true; } - } - - private void Open() - { - RabbitMqClientEventSource.Log.ConnectionOpened(); - StartAndTune(); - _model0.ConnectionOpen(_config.VirtualHost); - } - - private void StartAndTune() - { - var connectionStartCell = new BlockingCell(); - _model0.m_connectionStartCell = connectionStartCell; - _model0.HandshakeContinuationTimeout = _config.HandshakeContinuationTimeout; - _frameHandler.ReadTimeout = _config.HandshakeContinuationTimeout; - _frameHandler.SendHeader(); - ConnectionStartDetails connectionStart = connectionStartCell.WaitForValue(); - - if (connectionStart is null) + internal void HandleConnectionBlocked(string reason) { - throw new IOException("connection.start was never received, likely due to a network timeout"); + if (!_connectionBlockedWrapper.IsEmpty) + { + _connectionBlockedWrapper.Invoke(this, new ConnectionBlockedEventArgs(reason)); + } } - ServerProperties = connectionStart.m_serverProperties; + internal void HandleConnectionUnblocked() + { + if (!_connectionUnblockedWrapper.IsEmpty) + { + _connectionUnblockedWrapper.Invoke(this, EventArgs.Empty); + } + } - var serverVersion = new AmqpVersion(connectionStart.m_versionMajor, connectionStart.m_versionMinor); - if (!serverVersion.Equals(Protocol.Version)) + private void Open() { - TerminateMainloop(); - FinishClose(); - throw new ProtocolVersionMismatchException(Protocol.MajorVersion, Protocol.MinorVersion, serverVersion.Major, serverVersion.Minor); + RabbitMqClientEventSource.Log.ConnectionOpened(); + StartAndTune(); + _model0.ConnectionOpen(_config.VirtualHost); } - // FIXME: parse out locales properly! - ConnectionTuneDetails connectionTune = default; - bool tuned = false; - try + private void StartAndTune() { - string mechanismsString = Encoding.UTF8.GetString(connectionStart.m_mechanisms); - IAuthMechanismFactory mechanismFactory = GetAuthMechanismFactory(mechanismsString); - IAuthMechanism mechanism = mechanismFactory.GetInstance(); - byte[]? challenge = null; - do + var connectionStartCell = new BlockingCell(); + _model0.m_connectionStartCell = connectionStartCell; + _model0.HandshakeContinuationTimeout = _config.HandshakeContinuationTimeout; + _frameHandler.ReadTimeout = _config.HandshakeContinuationTimeout; + _frameHandler.SendHeader(); + + ConnectionStartDetails connectionStart = connectionStartCell.WaitForValue(); + + if (connectionStart is null) { - byte[] response = mechanism.handleChallenge(challenge, _config); - ConnectionSecureOrTune res; - if (challenge is null) - { - res = _model0.ConnectionStartOk(ClientProperties, - mechanismFactory.Name, - response, - "en_US"); - } - else - { - res = _model0.ConnectionSecureOk(response); - } + throw new IOException("connection.start was never received, likely due to a network timeout"); + } - if (res.m_challenge is null) - { - connectionTune = res.m_tuneDetails; - tuned = true; - } - else + ServerProperties = connectionStart.m_serverProperties; + + var serverVersion = new AmqpVersion(connectionStart.m_versionMajor, connectionStart.m_versionMinor); + if (!serverVersion.Equals(Protocol.Version)) + { + TerminateMainloop(); + FinishClose(); + throw new ProtocolVersionMismatchException(Protocol.MajorVersion, Protocol.MinorVersion, serverVersion.Major, serverVersion.Minor); + } + + // FIXME: parse out locales properly! + ConnectionTuneDetails connectionTune = default; + bool tuned = false; + try + { + string mechanismsString = Encoding.UTF8.GetString(connectionStart.m_mechanisms); + IAuthMechanismFactory mechanismFactory = GetAuthMechanismFactory(mechanismsString); + IAuthMechanism mechanism = mechanismFactory.GetInstance(); + byte[]? challenge = null; + do { - challenge = res.m_challenge; + byte[] response = mechanism.handleChallenge(challenge, _config); + ConnectionSecureOrTune res; + if (challenge is null) + { + res = _model0.ConnectionStartOk(ClientProperties, + mechanismFactory.Name, + response, + "en_US"); + } + else + { + res = _model0.ConnectionSecureOk(response); + } + + if (res.m_challenge is null) + { + connectionTune = res.m_tuneDetails; + tuned = true; + } + else + { + challenge = res.m_challenge; + } } + while (!tuned); } - while (!tuned); - } - catch (OperationInterruptedException e) - { - if (e.ShutdownReason != null && e.ShutdownReason.ReplyCode == Constants.AccessRefused) + catch (OperationInterruptedException e) { - throw new AuthenticationFailureException(e.ShutdownReason.ReplyText); + if (e.ShutdownReason != null && e.ShutdownReason.ReplyCode == Constants.AccessRefused) + { + throw new AuthenticationFailureException(e.ShutdownReason.ReplyText); + } + throw new PossibleAuthenticationFailureException( + "Possibly caused by authentication failure", e); } - throw new PossibleAuthenticationFailureException( - "Possibly caused by authentication failure", e); - } - ushort channelMax = (ushort)NegotiatedMaxValue(_config.MaxChannelCount, connectionTune.m_channelMax); - _sessionManager = new SessionManager(this, channelMax); + ushort channelMax = (ushort)NegotiatedMaxValue(_config.MaxChannelCount, connectionTune.m_channelMax); + _sessionManager = new SessionManager(this, channelMax); - uint frameMax = NegotiatedMaxValue(_config.MaxFrameSize, connectionTune.m_frameMax); - FrameMax = frameMax; - MaxPayloadSize = frameMax == 0 ? int.MaxValue : (int)frameMax - Client.Impl.Framing.BaseFrameSize; + uint frameMax = NegotiatedMaxValue(_config.MaxFrameSize, connectionTune.m_frameMax); + FrameMax = frameMax; + MaxPayloadSize = frameMax == 0 ? int.MaxValue : (int)frameMax - Client.Impl.Framing.BaseFrameSize; - uint heartbeatInSeconds = NegotiatedMaxValue((uint)_config.HeartbeatInterval.TotalSeconds, (uint)connectionTune.m_heartbeatInSeconds); - Heartbeat = TimeSpan.FromSeconds(heartbeatInSeconds); + uint heartbeatInSeconds = NegotiatedMaxValue((uint)_config.HeartbeatInterval.TotalSeconds, (uint)connectionTune.m_heartbeatInSeconds); + Heartbeat = TimeSpan.FromSeconds(heartbeatInSeconds); - _model0.ConnectionTuneOk(channelMax, frameMax, (ushort)Heartbeat.TotalSeconds); + _model0.ConnectionTuneOk(channelMax, frameMax, (ushort)Heartbeat.TotalSeconds); - // now we can start heartbeat timers - MaybeStartHeartbeatTimers(); - } + // now we can start heartbeat timers + MaybeStartHeartbeatTimers(); + } - private IAuthMechanismFactory GetAuthMechanismFactory(string supportedMechanismNames) - { - // Our list is in order of preference, the server one is not. - foreach (var factory in _config.AuthMechanisms) + private IAuthMechanismFactory GetAuthMechanismFactory(string supportedMechanismNames) { - if (supportedMechanismNames.IndexOf(factory.Name, StringComparison.OrdinalIgnoreCase) >= 0) + // Our list is in order of preference, the server one is not. + foreach (var factory in _config.AuthMechanisms) { - return factory; + if (supportedMechanismNames.IndexOf(factory.Name, StringComparison.OrdinalIgnoreCase) >= 0) + { + return factory; + } } - } - throw new IOException($"No compatible authentication mechanism found - server offered [{supportedMechanismNames}]"); - } + throw new IOException($"No compatible authentication mechanism found - server offered [{supportedMechanismNames}]"); + } - private static uint NegotiatedMaxValue(uint clientValue, uint serverValue) - { - return (clientValue == 0 || serverValue == 0) ? - Math.Max(clientValue, serverValue) : - Math.Min(clientValue, serverValue); + private static uint NegotiatedMaxValue(uint clientValue, uint serverValue) + { + return (clientValue == 0 || serverValue == 0) ? + Math.Max(clientValue, serverValue) : + Math.Min(clientValue, serverValue); + } } } diff --git a/projects/RabbitMQ.Client/client/impl/Connection.Heartbeat.cs b/projects/RabbitMQ.Client/client/impl/Connection.Heartbeat.cs index dca0ae5677..bd3ae7d7dc 100644 --- a/projects/RabbitMQ.Client/client/impl/Connection.Heartbeat.cs +++ b/projects/RabbitMQ.Client/client/impl/Connection.Heartbeat.cs @@ -33,135 +33,136 @@ using System.IO; using System.Threading; -namespace RabbitMQ.Client.Framing.Impl; - -#nullable enable -internal sealed partial class Connection +namespace RabbitMQ.Client.Framing.Impl { - private TimeSpan _heartbeat; - private TimeSpan _heartbeatTimeSpan; - private int _missedHeartbeats; - private bool _heartbeatDetected; +#nullable enable + internal sealed partial class Connection + { + private TimeSpan _heartbeat; + private TimeSpan _heartbeatTimeSpan; + private int _missedHeartbeats; + private bool _heartbeatDetected; - private Timer? _heartbeatWriteTimer; - private Timer? _heartbeatReadTimer; + private Timer? _heartbeatWriteTimer; + private Timer? _heartbeatReadTimer; - public TimeSpan Heartbeat - { - get => _heartbeat; - set + public TimeSpan Heartbeat { - _heartbeat = value; - // timers fire at slightly below half the interval to avoid race - // conditions - _heartbeatTimeSpan = TimeSpan.FromMilliseconds(_heartbeat.TotalMilliseconds / 4); - _frameHandler.ReadTimeout = TimeSpan.FromMilliseconds(_heartbeat.TotalMilliseconds * 2); + get => _heartbeat; + set + { + _heartbeat = value; + // timers fire at slightly below half the interval to avoid race + // conditions + _heartbeatTimeSpan = TimeSpan.FromMilliseconds(_heartbeat.TotalMilliseconds / 4); + _frameHandler.ReadTimeout = TimeSpan.FromMilliseconds(_heartbeat.TotalMilliseconds * 2); + } } - } - private void MaybeStartHeartbeatTimers() - { - if (Heartbeat != TimeSpan.Zero) + private void MaybeStartHeartbeatTimers() { - _heartbeatWriteTimer ??= new Timer(HeartbeatWriteTimerCallback, null, 200, Timeout.Infinite); - _heartbeatReadTimer ??= new Timer(HeartbeatReadTimerCallback, null, 300, Timeout.Infinite); + if (Heartbeat != TimeSpan.Zero) + { + _heartbeatWriteTimer ??= new Timer(HeartbeatWriteTimerCallback, null, 200, Timeout.Infinite); + _heartbeatReadTimer ??= new Timer(HeartbeatReadTimerCallback, null, 300, Timeout.Infinite); + } } - } - - private void MaybeStopHeartbeatTimers() - { - NotifyHeartbeatListener(); - _heartbeatReadTimer?.Dispose(); - _heartbeatWriteTimer?.Dispose(); - } - private void NotifyHeartbeatListener() - { - _heartbeatDetected = true; - } - - private void HeartbeatReadTimerCallback(object? state) - { - if (_heartbeatReadTimer is null) + private void MaybeStopHeartbeatTimers() { - return; + NotifyHeartbeatListener(); + _heartbeatReadTimer?.Dispose(); + _heartbeatWriteTimer?.Dispose(); } - bool shouldTerminate = false; + private void NotifyHeartbeatListener() + { + _heartbeatDetected = true; + } - try + private void HeartbeatReadTimerCallback(object? state) { - if (!_closed) + if (_heartbeatReadTimer is null) + { + return; + } + + bool shouldTerminate = false; + + try { - if (_heartbeatDetected) + if (!_closed) { - _heartbeatDetected = false; - _missedHeartbeats = 0; + if (_heartbeatDetected) + { + _heartbeatDetected = false; + _missedHeartbeats = 0; + } + else + { + _missedHeartbeats++; + } + + // We check against 8 = 2 * 4 because we need to wait for at + // least two complete heartbeat setting intervals before + // complaining, and we've set the socket timeout to a quarter + // of the heartbeat setting in setHeartbeat above. + if (_missedHeartbeats > 2 * 4) + { + var eose = new EndOfStreamException($"Heartbeat missing with heartbeat == {_heartbeat} seconds"); + LogCloseError(eose.Message, eose); + HandleMainLoopException(new ShutdownEventArgs(ShutdownInitiator.Library, 0, "End of stream", eose)); + shouldTerminate = true; + } } - else + + if (shouldTerminate) { - _missedHeartbeats++; + TerminateMainloop(); + FinishClose(); } - - // We check against 8 = 2 * 4 because we need to wait for at - // least two complete heartbeat setting intervals before - // complaining, and we've set the socket timeout to a quarter - // of the heartbeat setting in setHeartbeat above. - if (_missedHeartbeats > 2 * 4) + else { - var eose = new EndOfStreamException($"Heartbeat missing with heartbeat == {_heartbeat} seconds"); - LogCloseError(eose.Message, eose); - HandleMainLoopException(new ShutdownEventArgs(ShutdownInitiator.Library, 0, "End of stream", eose)); - shouldTerminate = true; + _heartbeatReadTimer?.Change((int)Heartbeat.TotalMilliseconds, Timeout.Infinite); } } - - if (shouldTerminate) + catch (ObjectDisposedException) { - TerminateMainloop(); - FinishClose(); + // timer is already disposed, + // e.g. due to shutdown } - else + catch (NullReferenceException) { - _heartbeatReadTimer?.Change((int)Heartbeat.TotalMilliseconds, Timeout.Infinite); + // timer has already been disposed from a different thread after null check + // this event should be rare } } - catch (ObjectDisposedException) - { - // timer is already disposed, - // e.g. due to shutdown - } - catch (NullReferenceException) - { - // timer has already been disposed from a different thread after null check - // this event should be rare - } - } - private void HeartbeatWriteTimerCallback(object? state) - { - if (_heartbeatWriteTimer is null) + private void HeartbeatWriteTimerCallback(object? state) { - return; - } + if (_heartbeatWriteTimer is null) + { + return; + } - try - { - if (!_closed) + try { - Write(Client.Impl.Framing.Heartbeat.GetHeartbeatFrame()); - _heartbeatWriteTimer?.Change((int)_heartbeatTimeSpan.TotalMilliseconds, Timeout.Infinite); + if (!_closed) + { + Write(Client.Impl.Framing.Heartbeat.GetHeartbeatFrame()); + _heartbeatWriteTimer?.Change((int)_heartbeatTimeSpan.TotalMilliseconds, Timeout.Infinite); + } + } + catch (ObjectDisposedException) + { + // timer is already disposed, + // e.g. due to shutdown + } + catch (Exception) + { + // ignore, let the read callback detect + // peer unavailability. See rabbitmq/rabbitmq-dotnet-client#638 for details. } - } - catch (ObjectDisposedException) - { - // timer is already disposed, - // e.g. due to shutdown - } - catch (Exception) - { - // ignore, let the read callback detect - // peer unavailability. See rabbitmq/rabbitmq-dotnet-client#638 for details. } } } diff --git a/projects/RabbitMQ.Client/client/impl/Connection.Receive.cs b/projects/RabbitMQ.Client/client/impl/Connection.Receive.cs index 12778a3b72..38274cea51 100644 --- a/projects/RabbitMQ.Client/client/impl/Connection.Receive.cs +++ b/projects/RabbitMQ.Client/client/impl/Connection.Receive.cs @@ -35,165 +35,166 @@ using RabbitMQ.Client.Exceptions; using RabbitMQ.Client.Impl; -namespace RabbitMQ.Client.Framing.Impl; - -#nullable enable -internal sealed partial class Connection +namespace RabbitMQ.Client.Framing.Impl { - private readonly IFrameHandler _frameHandler; - private readonly Task _mainLoopTask; - - private void MainLoop() +#nullable enable + internal sealed partial class Connection { - try - { - ReceiveLoop(); - } - catch (EndOfStreamException eose) - { - // Possible heartbeat exception - HandleMainLoopException(new ShutdownEventArgs(ShutdownInitiator.Library, 0, "End of stream", eose)); - } - catch (HardProtocolException hpe) - { - HardProtocolExceptionHandler(hpe); - } - catch (Exception ex) + private readonly IFrameHandler _frameHandler; + private readonly Task _mainLoopTask; + + private void MainLoop() { - HandleMainLoopException(new ShutdownEventArgs(ShutdownInitiator.Library, Constants.InternalError, "Unexpected Exception", ex)); - } + try + { + ReceiveLoop(); + } + catch (EndOfStreamException eose) + { + // Possible heartbeat exception + HandleMainLoopException(new ShutdownEventArgs(ShutdownInitiator.Library, 0, "End of stream", eose)); + } + catch (HardProtocolException hpe) + { + HardProtocolExceptionHandler(hpe); + } + catch (Exception ex) + { + HandleMainLoopException(new ShutdownEventArgs(ShutdownInitiator.Library, Constants.InternalError, "Unexpected Exception", ex)); + } - FinishClose(); - } + FinishClose(); + } - private void ReceiveLoop() - { - while (!_closed) + private void ReceiveLoop() { - InboundFrame frame = _frameHandler.ReadFrame(); - NotifyHeartbeatListener(); - - bool shallReturn = true; - if (frame.Channel == 0) + while (!_closed) { - if (frame.Type == FrameType.FrameHeartbeat) + InboundFrame frame = _frameHandler.ReadFrame(); + NotifyHeartbeatListener(); + + bool shallReturn = true; + if (frame.Channel == 0) { - // Ignore it: we've already just reset the heartbeat + if (frame.Type == FrameType.FrameHeartbeat) + { + // Ignore it: we've already just reset the heartbeat + } + else + { + // In theory, we could get non-connection.close-ok + // frames here while we're quiescing (m_closeReason != + // null). In practice, there's a limited number of + // things the server can ask of us on channel 0 - + // essentially, just connection.close. That, combined + // with the restrictions on pipelining, mean that + // we're OK here to handle channel 0 traffic in a + // quiescing situation, even though technically we + // should be ignoring everything except + // connection.close-ok. + shallReturn = _session0.HandleFrame(in frame); + } } else { - // In theory, we could get non-connection.close-ok - // frames here while we're quiescing (m_closeReason != - // null). In practice, there's a limited number of - // things the server can ask of us on channel 0 - - // essentially, just connection.close. That, combined - // with the restrictions on pipelining, mean that - // we're OK here to handle channel 0 traffic in a - // quiescing situation, even though technically we - // should be ignoring everything except - // connection.close-ok. - shallReturn = _session0.HandleFrame(in frame); + // If we're still m_running, but have a m_closeReason, + // then we must be quiescing, which means any inbound + // frames for non-zero channels (and any inbound + // commands on channel zero that aren't + // Connection.CloseOk) must be discarded. + if (_closeReason is null) + { + // No close reason, not quiescing the + // connection. Handle the frame. (Of course, the + // Session itself may be quiescing this particular + // channel, but that's none of our concern.) + shallReturn = _sessionManager.Lookup(frame.Channel).HandleFrame(in frame); + } } - } - else - { - // If we're still m_running, but have a m_closeReason, - // then we must be quiescing, which means any inbound - // frames for non-zero channels (and any inbound - // commands on channel zero that aren't - // Connection.CloseOk) must be discarded. - if (_closeReason is null) + + if (shallReturn) { - // No close reason, not quiescing the - // connection. Handle the frame. (Of course, the - // Session itself may be quiescing this particular - // channel, but that's none of our concern.) - shallReturn = _sessionManager.Lookup(frame.Channel).HandleFrame(in frame); + frame.ReturnPayload(); } } - - if (shallReturn) - { - frame.ReturnPayload(); - } } - } - /// - /// May be called more than once. Should therefore be idempotent. - /// - private void TerminateMainloop() - { - MaybeStopHeartbeatTimers(); - } - - private void HandleMainLoopException(ShutdownEventArgs reason) - { - if (!SetCloseReason(reason)) + /// + /// May be called more than once. Should therefore be idempotent. + /// + private void TerminateMainloop() { - LogCloseError("Unexpected Main Loop Exception while closing: " + reason, new Exception(reason.ToString())); - return; + MaybeStopHeartbeatTimers(); } - OnShutdown(reason); - LogCloseError($"Unexpected connection closure: {reason}", new Exception(reason.ToString())); - } + private void HandleMainLoopException(ShutdownEventArgs reason) + { + if (!SetCloseReason(reason)) + { + LogCloseError("Unexpected Main Loop Exception while closing: " + reason, new Exception(reason.ToString())); + return; + } - private void HardProtocolExceptionHandler(HardProtocolException hpe) - { - if (SetCloseReason(hpe.ShutdownReason)) + OnShutdown(reason); + LogCloseError($"Unexpected connection closure: {reason}", new Exception(reason.ToString())); + } + + private void HardProtocolExceptionHandler(HardProtocolException hpe) { - OnShutdown(hpe.ShutdownReason); - _session0.SetSessionClosing(false); - try + if (SetCloseReason(hpe.ShutdownReason)) { - var cmd = new ConnectionClose(hpe.ShutdownReason.ReplyCode, hpe.ShutdownReason.ReplyText, 0, 0); - _session0.Transmit(ref cmd); - ClosingLoop(); + OnShutdown(hpe.ShutdownReason); + _session0.SetSessionClosing(false); + try + { + var cmd = new ConnectionClose(hpe.ShutdownReason.ReplyCode, hpe.ShutdownReason.ReplyText, 0, 0); + _session0.Transmit(ref cmd); + ClosingLoop(); + } + catch (IOException ioe) + { + LogCloseError("Broker closed socket unexpectedly", ioe); + } } - catch (IOException ioe) + else { - LogCloseError("Broker closed socket unexpectedly", ioe); + LogCloseError("Hard Protocol Exception occurred while closing the connection", hpe); } } - else - { - LogCloseError("Hard Protocol Exception occurred while closing the connection", hpe); - } - } - /// - /// Loop only used while quiescing. Use only to cleanly close connection - /// - private void ClosingLoop() - { - try - { - _frameHandler.ReadTimeout = TimeSpan.Zero; - // Wait for response/socket closure or timeout - ReceiveLoop(); - } - catch (ObjectDisposedException ode) + /// + /// Loop only used while quiescing. Use only to cleanly close connection + /// + private void ClosingLoop() { - if (!_closed) + try { - LogCloseError("Connection didn't close cleanly", ode); + _frameHandler.ReadTimeout = TimeSpan.Zero; + // Wait for response/socket closure or timeout + ReceiveLoop(); } - } - catch (EndOfStreamException eose) - { - if (_model0.CloseReason is null) + catch (ObjectDisposedException ode) { - LogCloseError("Connection didn't close cleanly. Socket closed unexpectedly", eose); + if (!_closed) + { + LogCloseError("Connection didn't close cleanly", ode); + } + } + catch (EndOfStreamException eose) + { + if (_model0.CloseReason is null) + { + LogCloseError("Connection didn't close cleanly. Socket closed unexpectedly", eose); + } + } + catch (IOException ioe) + { + LogCloseError("Connection didn't close cleanly. Socket closed unexpectedly", ioe); + } + catch (Exception e) + { + LogCloseError("Unexpected exception while closing: ", e); } - } - catch (IOException ioe) - { - LogCloseError("Connection didn't close cleanly. Socket closed unexpectedly", ioe); - } - catch (Exception e) - { - LogCloseError("Unexpected exception while closing: ", e); } } } diff --git a/projects/RabbitMQ.Client/client/impl/Connection.cs b/projects/RabbitMQ.Client/client/impl/Connection.cs index 7cb5a710ea..f7036728d8 100644 --- a/projects/RabbitMQ.Client/client/impl/Connection.cs +++ b/projects/RabbitMQ.Client/client/impl/Connection.cs @@ -40,408 +40,409 @@ using RabbitMQ.Client.Impl; using RabbitMQ.Client.Logging; -namespace RabbitMQ.Client.Framing.Impl; - -#nullable enable -internal sealed partial class Connection : IConnection +namespace RabbitMQ.Client.Framing.Impl { - private bool _disposed; - private volatile bool _closed; +#nullable enable + internal sealed partial class Connection : IConnection + { + private bool _disposed; + private volatile bool _closed; - private readonly ConnectionConfig _config; - private readonly ModelBase _model0; - private readonly MainSession _session0; + private readonly ConnectionConfig _config; + private readonly ModelBase _model0; + private readonly MainSession _session0; - private Guid _id = Guid.NewGuid(); - private SessionManager _sessionManager; + private Guid _id = Guid.NewGuid(); + private SessionManager _sessionManager; - private ShutdownEventArgs? _closeReason; - public ShutdownEventArgs? CloseReason => Volatile.Read(ref _closeReason); + private ShutdownEventArgs? _closeReason; + public ShutdownEventArgs? CloseReason => Volatile.Read(ref _closeReason); - public Connection(ConnectionConfig config, IFrameHandler frameHandler) - { - _config = config; - _frameHandler = frameHandler; + public Connection(ConnectionConfig config, IFrameHandler frameHandler) + { + _config = config; + _frameHandler = frameHandler; - Action onException = (exception, context) => OnCallbackException(CallbackExceptionEventArgs.Build(exception, context)); - _callbackExceptionWrapper = new EventingWrapper(string.Empty, (exception, context) => { }); - _connectionBlockedWrapper = new EventingWrapper("OnConnectionBlocked", onException); - _connectionUnblockedWrapper = new EventingWrapper("OnConnectionUnblocked", onException); - _connectionShutdownWrapper = new EventingWrapper("OnShutdown", onException); + Action onException = (exception, context) => OnCallbackException(CallbackExceptionEventArgs.Build(exception, context)); + _callbackExceptionWrapper = new EventingWrapper(string.Empty, (exception, context) => { }); + _connectionBlockedWrapper = new EventingWrapper("OnConnectionBlocked", onException); + _connectionUnblockedWrapper = new EventingWrapper("OnConnectionUnblocked", onException); + _connectionShutdownWrapper = new EventingWrapper("OnShutdown", onException); - _sessionManager = new SessionManager(this, 0); - _session0 = new MainSession(this); - _model0 = new Model(_config, _session0); ; + _sessionManager = new SessionManager(this, 0); + _session0 = new MainSession(this); + _model0 = new Model(_config, _session0); ; - ClientProperties = new Dictionary(_config.ClientProperties) - { - ["capabilities"] = Protocol.Capabilities, - ["connection_name"] = ClientProvidedName - }; + ClientProperties = new Dictionary(_config.ClientProperties) + { + ["capabilities"] = Protocol.Capabilities, + ["connection_name"] = ClientProvidedName + }; - _mainLoopTask = Task.Factory.StartNew(MainLoop, TaskCreationOptions.LongRunning); - try - { - Open(); - } - catch - { - var ea = new ShutdownEventArgs(ShutdownInitiator.Library, Constants.InternalError, "FailedOpen"); - Close(ea, true, TimeSpan.FromSeconds(5)); - throw; + _mainLoopTask = Task.Factory.StartNew(MainLoop, TaskCreationOptions.LongRunning); + try + { + Open(); + } + catch + { + var ea = new ShutdownEventArgs(ShutdownInitiator.Library, Constants.InternalError, "FailedOpen"); + Close(ea, true, TimeSpan.FromSeconds(5)); + throw; + } } - } - public Guid Id => _id; + public Guid Id => _id; - public string? ClientProvidedName => _config.ClientProvidedName; + public string? ClientProvidedName => _config.ClientProvidedName; - public ushort ChannelMax => _sessionManager.ChannelMax; + public ushort ChannelMax => _sessionManager.ChannelMax; - public IDictionary ClientProperties { get; private set; } + public IDictionary ClientProperties { get; private set; } - public AmqpTcpEndpoint Endpoint => _frameHandler.Endpoint; + public AmqpTcpEndpoint Endpoint => _frameHandler.Endpoint; - public uint FrameMax { get; private set; } + public uint FrameMax { get; private set; } - public bool IsOpen => CloseReason is null; + public bool IsOpen => CloseReason is null; - public int LocalPort => _frameHandler.LocalPort; - public int RemotePort => _frameHandler.RemotePort; + public int LocalPort => _frameHandler.LocalPort; + public int RemotePort => _frameHandler.RemotePort; - public IDictionary? ServerProperties { get; private set; } + public IDictionary? ServerProperties { get; private set; } - public IList ShutdownReport => _shutdownReport; - private ShutdownReportEntry[] _shutdownReport = Array.Empty(); + public IList ShutdownReport => _shutdownReport; + private ShutdownReportEntry[] _shutdownReport = Array.Empty(); - ///Explicit implementation of IConnection.Protocol. - IProtocol IConnection.Protocol => Endpoint.Protocol; + ///Explicit implementation of IConnection.Protocol. + IProtocol IConnection.Protocol => Endpoint.Protocol; - ///Another overload of a Protocol property, useful - ///for exposing a tighter type. - internal ProtocolBase Protocol => (ProtocolBase)Endpoint.Protocol; + ///Another overload of a Protocol property, useful + ///for exposing a tighter type. + internal ProtocolBase Protocol => (ProtocolBase)Endpoint.Protocol; - ///Used for testing only. - internal IFrameHandler FrameHandler - { - get { return _frameHandler; } - } + ///Used for testing only. + internal IFrameHandler FrameHandler + { + get { return _frameHandler; } + } - public event EventHandler CallbackException - { - add => _callbackExceptionWrapper.AddHandler(value); - remove => _callbackExceptionWrapper.RemoveHandler(value); - } - private EventingWrapper _callbackExceptionWrapper; + public event EventHandler CallbackException + { + add => _callbackExceptionWrapper.AddHandler(value); + remove => _callbackExceptionWrapper.RemoveHandler(value); + } + private EventingWrapper _callbackExceptionWrapper; - public event EventHandler ConnectionBlocked - { - add => _connectionBlockedWrapper.AddHandler(value); - remove => _connectionBlockedWrapper.RemoveHandler(value); - } - private EventingWrapper _connectionBlockedWrapper; + public event EventHandler ConnectionBlocked + { + add => _connectionBlockedWrapper.AddHandler(value); + remove => _connectionBlockedWrapper.RemoveHandler(value); + } + private EventingWrapper _connectionBlockedWrapper; - public event EventHandler ConnectionUnblocked - { - add => _connectionUnblockedWrapper.AddHandler(value); - remove => _connectionUnblockedWrapper.RemoveHandler(value); - } - private EventingWrapper _connectionUnblockedWrapper; + public event EventHandler ConnectionUnblocked + { + add => _connectionUnblockedWrapper.AddHandler(value); + remove => _connectionUnblockedWrapper.RemoveHandler(value); + } + private EventingWrapper _connectionUnblockedWrapper; - public event EventHandler ConnectionShutdown - { - add + public event EventHandler ConnectionShutdown { - ThrowIfDisposed(); - var reason = CloseReason; - if (reason is null) + add { - _connectionShutdownWrapper.AddHandler(value); + ThrowIfDisposed(); + var reason = CloseReason; + if (reason is null) + { + _connectionShutdownWrapper.AddHandler(value); + } + else + { + value(this, reason); + } } - else + remove { - value(this, reason); + ThrowIfDisposed(); + _connectionShutdownWrapper.RemoveHandler(value); } } - remove + private EventingWrapper _connectionShutdownWrapper; + + /// + /// This event is never fired by non-recovering connections but it is a part of the interface. + /// + public event EventHandler RecoverySucceeded { - ThrowIfDisposed(); - _connectionShutdownWrapper.RemoveHandler(value); + add { } + remove { } } - } - private EventingWrapper _connectionShutdownWrapper; - /// - /// This event is never fired by non-recovering connections but it is a part of the interface. - /// - public event EventHandler RecoverySucceeded - { - add { } - remove { } - } - - /// - /// This event is never fired by non-recovering connections but it is a part of the interface. - /// - public event EventHandler ConnectionRecoveryError - { - add { } - remove { } - } - - /// - /// This event is never fired by non-recovering connections but it is a part of the interface. - /// - public event EventHandler ConsumerTagChangeAfterRecovery - { - add { } - remove { } - } - - /// - /// This event is never fired by non-recovering connections but it is a part of the interface. - /// - public event EventHandler QueueNameChangeAfterRecovery - { - add { } - remove { } - } + /// + /// This event is never fired by non-recovering connections but it is a part of the interface. + /// + public event EventHandler ConnectionRecoveryError + { + add { } + remove { } + } - internal void TakeOver(Connection other) - { - _callbackExceptionWrapper.Takeover(other._callbackExceptionWrapper); - _connectionBlockedWrapper.Takeover(other._connectionBlockedWrapper); - _connectionUnblockedWrapper.Takeover(other._connectionUnblockedWrapper); - _connectionShutdownWrapper.Takeover(other._connectionShutdownWrapper); - } + /// + /// This event is never fired by non-recovering connections but it is a part of the interface. + /// + public event EventHandler ConsumerTagChangeAfterRecovery + { + add { } + remove { } + } - public IModel CreateModel() - { - EnsureIsOpen(); - ISession session = CreateSession(); - var model = new Model(_config, session); - model._Private_ChannelOpen(); - return model; - } + /// + /// This event is never fired by non-recovering connections but it is a part of the interface. + /// + public event EventHandler QueueNameChangeAfterRecovery + { + add { } + remove { } + } - internal ISession CreateSession() - { - return _sessionManager.Create(); - } + internal void TakeOver(Connection other) + { + _callbackExceptionWrapper.Takeover(other._callbackExceptionWrapper); + _connectionBlockedWrapper.Takeover(other._connectionBlockedWrapper); + _connectionUnblockedWrapper.Takeover(other._connectionUnblockedWrapper); + _connectionShutdownWrapper.Takeover(other._connectionShutdownWrapper); + } - /// - /// The maximum payload size for this connection. - /// - /// Compared to unlimited, unlimited means here . - /// Also it is reduced by the required framing bytes as in . - internal int MaxPayloadSize { get; private set; } + public IModel CreateModel() + { + EnsureIsOpen(); + ISession session = CreateSession(); + var model = new Model(_config, session); + model._Private_ChannelOpen(); + return model; + } - internal void EnsureIsOpen() - { - if (!IsOpen) + internal ISession CreateSession() { - ThrowAlreadyClosedException(CloseReason!); + return _sessionManager.Create(); } - } - ///API-side invocation of connection.close with timeout. - public void Close(ushort reasonCode, string reasonText, TimeSpan timeout, bool abort) - { - Close(new ShutdownEventArgs(ShutdownInitiator.Application, reasonCode, reasonText), abort, timeout); - } + /// + /// The maximum payload size for this connection. + /// + /// Compared to unlimited, unlimited means here . + /// Also it is reduced by the required framing bytes as in . + internal int MaxPayloadSize { get; private set; } - ///Try to close connection in a graceful way - /// - /// - ///Shutdown reason contains code and text assigned when closing the connection, - ///as well as the information about what initiated the close - /// - /// - ///Abort flag, if true, signals to close the ongoing connection immediately - ///and do not report any errors if it was already closed. - /// - /// - ///Timeout determines how much time internal close operations should be given - ///to complete. - /// - /// - internal void Close(ShutdownEventArgs reason, bool abort, TimeSpan timeout) - { - if (!SetCloseReason(reason)) + internal void EnsureIsOpen() { - if (!abort) + if (!IsOpen) { ThrowAlreadyClosedException(CloseReason!); } } - else + + ///API-side invocation of connection.close with timeout. + public void Close(ushort reasonCode, string reasonText, TimeSpan timeout, bool abort) { - OnShutdown(reason); - _session0.SetSessionClosing(false); + Close(new ShutdownEventArgs(ShutdownInitiator.Application, reasonCode, reasonText), abort, timeout); + } - try + ///Try to close connection in a graceful way + /// + /// + ///Shutdown reason contains code and text assigned when closing the connection, + ///as well as the information about what initiated the close + /// + /// + ///Abort flag, if true, signals to close the ongoing connection immediately + ///and do not report any errors if it was already closed. + /// + /// + ///Timeout determines how much time internal close operations should be given + ///to complete. + /// + /// + internal void Close(ShutdownEventArgs reason, bool abort, TimeSpan timeout) + { + if (!SetCloseReason(reason)) { - // Try to send connection.close wait for CloseOk in the MainLoop - if (!_closed) + if (!abort) { - var cmd = new ConnectionClose(reason.ReplyCode, reason.ReplyText, 0, 0); - _session0.Transmit(ref cmd); + ThrowAlreadyClosedException(CloseReason!); } } - catch (AlreadyClosedException) + else { - if (!abort) + OnShutdown(reason); + _session0.SetSessionClosing(false); + + try { - throw; + // Try to send connection.close wait for CloseOk in the MainLoop + if (!_closed) + { + var cmd = new ConnectionClose(reason.ReplyCode, reason.ReplyText, 0, 0); + _session0.Transmit(ref cmd); + } } - } -#pragma warning disable 0168 - catch (NotSupportedException nse) - { - // buffered stream had unread data in it and Flush() - // was called, ignore to not confuse the user - } -#pragma warning restore 0168 - catch (IOException ioe) - { - if (_model0.CloseReason is null) + catch (AlreadyClosedException) { if (!abort) { throw; } - else + } +#pragma warning disable 0168 + catch (NotSupportedException nse) + { + // buffered stream had unread data in it and Flush() + // was called, ignore to not confuse the user + } +#pragma warning restore 0168 + catch (IOException ioe) + { + if (_model0.CloseReason is null) { - LogCloseError("Couldn't close connection cleanly. Socket closed unexpectedly", ioe); + if (!abort) + { + throw; + } + else + { + LogCloseError("Couldn't close connection cleanly. Socket closed unexpectedly", ioe); + } } } + finally + { + TerminateMainloop(); + } } - finally + + try { - TerminateMainloop(); + if (!_mainLoopTask.Wait(timeout)) + { + _frameHandler.Close(); + } } - } - - try - { - if (!_mainLoopTask.Wait(timeout)) + catch (AggregateException) { _frameHandler.Close(); } } - catch (AggregateException) - { - _frameHandler.Close(); - } - } - internal void InternalClose(ShutdownEventArgs reason) - { - if (!SetCloseReason(reason)) + internal void InternalClose(ShutdownEventArgs reason) { - if (_closed) + if (!SetCloseReason(reason)) { - ThrowAlreadyClosedException(CloseReason!); + if (_closed) + { + ThrowAlreadyClosedException(CloseReason!); + } + // We are quiescing, but still allow for server-close } - // We are quiescing, but still allow for server-close - } - - OnShutdown(reason); - _session0.SetSessionClosing(true); - TerminateMainloop(); - } - // Only call at the end of the Mainloop or HeartbeatLoop - - private void FinishClose() - { - _closed = true; - MaybeStopHeartbeatTimers(); + OnShutdown(reason); + _session0.SetSessionClosing(true); + TerminateMainloop(); + } - _frameHandler.Close(); - _model0.SetCloseReason(CloseReason); - _model0.FinishClose(); - RabbitMqClientEventSource.Log.ConnectionClosed(); - } + // Only call at the end of the Mainloop or HeartbeatLoop - ///Broadcasts notification of the final shutdown of the connection. - private void OnShutdown(ShutdownEventArgs reason) - { - ThrowIfDisposed(); - _connectionShutdownWrapper.Invoke(this, reason); - } + private void FinishClose() + { + _closed = true; + MaybeStopHeartbeatTimers(); - private bool SetCloseReason(ShutdownEventArgs reason) - { - return System.Threading.Interlocked.CompareExchange(ref _closeReason, reason, null) is null; - } + _frameHandler.Close(); + _model0.SetCloseReason(CloseReason); + _model0.FinishClose(); + RabbitMqClientEventSource.Log.ConnectionClosed(); + } - private void LogCloseError(string error, Exception ex) - { - ESLog.Error(error, ex); + ///Broadcasts notification of the final shutdown of the connection. + private void OnShutdown(ShutdownEventArgs reason) + { + ThrowIfDisposed(); + _connectionShutdownWrapper.Invoke(this, reason); + } - lock (_shutdownReport) + private bool SetCloseReason(ShutdownEventArgs reason) { - var replacement = new ShutdownReportEntry[_shutdownReport.Length + 1]; - replacement[replacement.Length - 1] = new ShutdownReportEntry(error, ex); - _shutdownReport.CopyTo(replacement.AsSpan()); - _shutdownReport = replacement; + return System.Threading.Interlocked.CompareExchange(ref _closeReason, reason, null) is null; } - } - internal void OnCallbackException(CallbackExceptionEventArgs args) - { - _callbackExceptionWrapper.Invoke(this, args); - } + private void LogCloseError(string error, Exception ex) + { + ESLog.Error(error, ex); - internal void Write(ReadOnlyMemory memory) - { - _frameHandler.Write(memory); - } + lock (_shutdownReport) + { + var replacement = new ShutdownReportEntry[_shutdownReport.Length + 1]; + replacement[replacement.Length - 1] = new ShutdownReportEntry(error, ex); + _shutdownReport.CopyTo(replacement.AsSpan()); + _shutdownReport = replacement; + } + } - public void Dispose() - { - if (_disposed) + internal void OnCallbackException(CallbackExceptionEventArgs args) { - return; + _callbackExceptionWrapper.Invoke(this, args); } - try + internal void Write(ReadOnlyMemory memory) { - this.Abort(InternalConstants.DefaultConnectionAbortTimeout); - _mainLoopTask.Wait(); + _frameHandler.Write(memory); } - catch (OperationInterruptedException) + + public void Dispose() { - // ignored, see rabbitmq/rabbitmq-dotnet-client#133 + if (_disposed) + { + return; + } + + try + { + this.Abort(InternalConstants.DefaultConnectionAbortTimeout); + _mainLoopTask.Wait(); + } + catch (OperationInterruptedException) + { + // ignored, see rabbitmq/rabbitmq-dotnet-client#133 + } + finally + { + _disposed = true; + } } - finally + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void ThrowIfDisposed() { - _disposed = true; + if (_disposed) + { + ThrowObjectDisposedException(); + } + + static void ThrowObjectDisposedException() + { + throw new ObjectDisposedException(typeof(Connection).FullName); + } } - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void ThrowIfDisposed() - { - if (_disposed) + public override string ToString() { - ThrowObjectDisposedException(); + return $"Connection({_id},{Endpoint})"; } - static void ThrowObjectDisposedException() + private static void ThrowAlreadyClosedException(ShutdownEventArgs closeReason) { - throw new ObjectDisposedException(typeof(Connection).FullName); + throw new AlreadyClosedException(closeReason); } } - - public override string ToString() - { - return $"Connection({_id},{Endpoint})"; - } - - private static void ThrowAlreadyClosedException(ShutdownEventArgs closeReason) - { - throw new AlreadyClosedException(closeReason); - } } diff --git a/projects/RabbitMQ.Client/client/impl/ConnectionSecureOrTune.cs b/projects/RabbitMQ.Client/client/impl/ConnectionSecureOrTune.cs index cf2a8716f2..addc36e00c 100644 --- a/projects/RabbitMQ.Client/client/impl/ConnectionSecureOrTune.cs +++ b/projects/RabbitMQ.Client/client/impl/ConnectionSecureOrTune.cs @@ -29,24 +29,25 @@ // Copyright (c) 2007-2020 VMware, Inc. All rights reserved. //--------------------------------------------------------------------------- -namespace RabbitMQ.Client.Impl; - -///Essential information from an incoming Connection.Tune -///method. -internal struct ConnectionTuneDetails +namespace RabbitMQ.Client.Impl { - ///The peer's suggested channel-max parameter. - public ushort m_channelMax; + ///Essential information from an incoming Connection.Tune + ///method. + internal struct ConnectionTuneDetails + { + ///The peer's suggested channel-max parameter. + public ushort m_channelMax; - ///The peer's suggested frame-max parameter. - public uint m_frameMax; + ///The peer's suggested frame-max parameter. + public uint m_frameMax; - ///The peer's suggested heartbeat parameter. - public ushort m_heartbeatInSeconds; -} + ///The peer's suggested heartbeat parameter. + public ushort m_heartbeatInSeconds; + } -internal class ConnectionSecureOrTune -{ - public byte[] m_challenge; - public ConnectionTuneDetails m_tuneDetails; + internal class ConnectionSecureOrTune + { + public byte[] m_challenge; + public ConnectionTuneDetails m_tuneDetails; + } } diff --git a/projects/RabbitMQ.Client/client/impl/ConnectionStartDetails.cs b/projects/RabbitMQ.Client/client/impl/ConnectionStartDetails.cs index e178ce72c0..bb540c045a 100644 --- a/projects/RabbitMQ.Client/client/impl/ConnectionStartDetails.cs +++ b/projects/RabbitMQ.Client/client/impl/ConnectionStartDetails.cs @@ -31,13 +31,14 @@ using System.Collections.Generic; -namespace RabbitMQ.Client.Impl; - -internal class ConnectionStartDetails +namespace RabbitMQ.Client.Impl { - public byte[] m_locales; - public byte[] m_mechanisms; - public IDictionary m_serverProperties; - public byte m_versionMajor; - public byte m_versionMinor; + internal class ConnectionStartDetails + { + public byte[] m_locales; + public byte[] m_mechanisms; + public IDictionary m_serverProperties; + public byte m_versionMajor; + public byte m_versionMinor; + } } diff --git a/projects/RabbitMQ.Client/client/impl/ConsumerDispatching/AsyncConsumerDispatcher.cs b/projects/RabbitMQ.Client/client/impl/ConsumerDispatching/AsyncConsumerDispatcher.cs index c380c57b1b..d51177da06 100644 --- a/projects/RabbitMQ.Client/client/impl/ConsumerDispatching/AsyncConsumerDispatcher.cs +++ b/projects/RabbitMQ.Client/client/impl/ConsumerDispatching/AsyncConsumerDispatcher.cs @@ -4,44 +4,45 @@ using RabbitMQ.Client.Events; using RabbitMQ.Client.Impl; -namespace RabbitMQ.Client.ConsumerDispatching; - -#nullable enable -internal sealed class AsyncConsumerDispatcher : ConsumerDispatcherChannelBase +namespace RabbitMQ.Client.ConsumerDispatching { - public AsyncConsumerDispatcher(ModelBase model, int concurrency) - : base(model, concurrency) +#nullable enable + internal sealed class AsyncConsumerDispatcher : ConsumerDispatcherChannelBase { - } + public AsyncConsumerDispatcher(ModelBase model, int concurrency) + : base(model, concurrency) + { + } - protected override async Task ProcessChannelAsync() - { - while (await _reader.WaitToReadAsync().ConfigureAwait(false)) + protected override async Task ProcessChannelAsync() { - while (_reader.TryRead(out var work)) + while (await _reader.WaitToReadAsync().ConfigureAwait(false)) { - try + while (_reader.TryRead(out var work)) { - var task = work.WorkType switch + try { - WorkType.Deliver => work.AsyncConsumer.HandleBasicDeliver(work.ConsumerTag, work.DeliveryTag, work.Redelivered, work.Exchange, work.RoutingKey, work.BasicProperties, work.Body), - WorkType.Cancel => work.AsyncConsumer.HandleBasicCancel(work.ConsumerTag), - WorkType.CancelOk => work.AsyncConsumer.HandleBasicCancelOk(work.ConsumerTag), - WorkType.ConsumeOk => work.AsyncConsumer.HandleBasicConsumeOk(work.ConsumerTag), - WorkType.Shutdown => work.AsyncConsumer.HandleModelShutdown(_model, work.Reason), - _ => Task.CompletedTask - }; - await task.ConfigureAwait(false); - } - catch (Exception e) - { - _model.OnCallbackException(CallbackExceptionEventArgs.Build(e, work.WorkType.ToString(), work.Consumer)); - } - finally - { - if (work.RentedArray != null) + var task = work.WorkType switch + { + WorkType.Deliver => work.AsyncConsumer.HandleBasicDeliver(work.ConsumerTag, work.DeliveryTag, work.Redelivered, work.Exchange, work.RoutingKey, work.BasicProperties, work.Body), + WorkType.Cancel => work.AsyncConsumer.HandleBasicCancel(work.ConsumerTag), + WorkType.CancelOk => work.AsyncConsumer.HandleBasicCancelOk(work.ConsumerTag), + WorkType.ConsumeOk => work.AsyncConsumer.HandleBasicConsumeOk(work.ConsumerTag), + WorkType.Shutdown => work.AsyncConsumer.HandleModelShutdown(_model, work.Reason), + _ => Task.CompletedTask + }; + await task.ConfigureAwait(false); + } + catch (Exception e) + { + _model.OnCallbackException(CallbackExceptionEventArgs.Build(e, work.WorkType.ToString(), work.Consumer)); + } + finally { - ArrayPool.Shared.Return(work.RentedArray); + if (work.RentedArray != null) + { + ArrayPool.Shared.Return(work.RentedArray); + } } } } diff --git a/projects/RabbitMQ.Client/client/impl/ConsumerDispatching/ConsumerDispatcher.cs b/projects/RabbitMQ.Client/client/impl/ConsumerDispatching/ConsumerDispatcher.cs index 6146769c75..37d0c69366 100644 --- a/projects/RabbitMQ.Client/client/impl/ConsumerDispatching/ConsumerDispatcher.cs +++ b/projects/RabbitMQ.Client/client/impl/ConsumerDispatching/ConsumerDispatcher.cs @@ -4,54 +4,55 @@ using RabbitMQ.Client.Events; using RabbitMQ.Client.Impl; -namespace RabbitMQ.Client.ConsumerDispatching; - -#nullable enable -internal sealed class ConsumerDispatcher : ConsumerDispatcherChannelBase +namespace RabbitMQ.Client.ConsumerDispatching { - public ConsumerDispatcher(ModelBase model, int concurrency) - : base(model, concurrency) +#nullable enable + internal sealed class ConsumerDispatcher : ConsumerDispatcherChannelBase { - } + public ConsumerDispatcher(ModelBase model, int concurrency) + : base(model, concurrency) + { + } - protected override async Task ProcessChannelAsync() - { - while (await _reader.WaitToReadAsync().ConfigureAwait(false)) + protected override async Task ProcessChannelAsync() { - while (_reader.TryRead(out var work)) + while (await _reader.WaitToReadAsync().ConfigureAwait(false)) { - try + while (_reader.TryRead(out var work)) { - var consumer = work.Consumer; - var consumerTag = work.ConsumerTag; - switch (work.WorkType) + try { - case WorkType.Deliver: - consumer.HandleBasicDeliver(consumerTag, work.DeliveryTag, work.Redelivered, work.Exchange, work.RoutingKey, work.BasicProperties, work.Body); - break; - case WorkType.Cancel: - consumer.HandleBasicCancel(consumerTag); - break; - case WorkType.CancelOk: - consumer.HandleBasicCancelOk(consumerTag); - break; - case WorkType.ConsumeOk: - consumer.HandleBasicConsumeOk(consumerTag); - break; - case WorkType.Shutdown: - consumer.HandleModelShutdown(_model, work.Reason); - break; + var consumer = work.Consumer; + var consumerTag = work.ConsumerTag; + switch (work.WorkType) + { + case WorkType.Deliver: + consumer.HandleBasicDeliver(consumerTag, work.DeliveryTag, work.Redelivered, work.Exchange, work.RoutingKey, work.BasicProperties, work.Body); + break; + case WorkType.Cancel: + consumer.HandleBasicCancel(consumerTag); + break; + case WorkType.CancelOk: + consumer.HandleBasicCancelOk(consumerTag); + break; + case WorkType.ConsumeOk: + consumer.HandleBasicConsumeOk(consumerTag); + break; + case WorkType.Shutdown: + consumer.HandleModelShutdown(_model, work.Reason); + break; + } } - } - catch (Exception e) - { - _model.OnCallbackException(CallbackExceptionEventArgs.Build(e, work.WorkType.ToString(), work.Consumer)); - } - finally - { - if (work.RentedArray != null) + catch (Exception e) + { + _model.OnCallbackException(CallbackExceptionEventArgs.Build(e, work.WorkType.ToString(), work.Consumer)); + } + finally { - ArrayPool.Shared.Return(work.RentedArray); + if (work.RentedArray != null) + { + ArrayPool.Shared.Return(work.RentedArray); + } } } } diff --git a/projects/RabbitMQ.Client/client/impl/ConsumerDispatching/ConsumerDispatcherBase.cs b/projects/RabbitMQ.Client/client/impl/ConsumerDispatching/ConsumerDispatcherBase.cs index 1d1963149b..c6b90f4287 100644 --- a/projects/RabbitMQ.Client/client/impl/ConsumerDispatching/ConsumerDispatcherBase.cs +++ b/projects/RabbitMQ.Client/client/impl/ConsumerDispatching/ConsumerDispatcherBase.cs @@ -2,67 +2,68 @@ using System.Runtime.CompilerServices; using System.Threading.Tasks; -namespace RabbitMQ.Client.ConsumerDispatching; - -#nullable enable -internal abstract class ConsumerDispatcherBase +namespace RabbitMQ.Client.ConsumerDispatching { - private static readonly FallbackConsumer fallbackConsumer = new FallbackConsumer(); - private readonly Dictionary _consumers; - - public IBasicConsumer? DefaultConsumer { get; set; } - - protected ConsumerDispatcherBase() +#nullable enable + internal abstract class ConsumerDispatcherBase { - _consumers = new Dictionary(); - } + private static readonly FallbackConsumer fallbackConsumer = new FallbackConsumer(); + private readonly Dictionary _consumers; - protected void AddConsumer(IBasicConsumer consumer, string tag) - { - lock (_consumers) + public IBasicConsumer? DefaultConsumer { get; set; } + + protected ConsumerDispatcherBase() { - _consumers[tag] = consumer; + _consumers = new Dictionary(); } - } - protected IBasicConsumer GetConsumerOrDefault(string tag) - { - lock (_consumers) + protected void AddConsumer(IBasicConsumer consumer, string tag) { - return _consumers.TryGetValue(tag, out var consumer) ? consumer : GetDefaultOrFallbackConsumer(); + lock (_consumers) + { + _consumers[tag] = consumer; + } } - } - public IBasicConsumer GetAndRemoveConsumer(string tag) - { - lock (_consumers) + protected IBasicConsumer GetConsumerOrDefault(string tag) { - return _consumers.Remove(tag, out var consumer) ? consumer : GetDefaultOrFallbackConsumer(); + lock (_consumers) + { + return _consumers.TryGetValue(tag, out var consumer) ? consumer : GetDefaultOrFallbackConsumer(); + } } - } - public Task ShutdownAsync(ShutdownEventArgs reason) - { - lock (_consumers) + public IBasicConsumer GetAndRemoveConsumer(string tag) { - foreach (KeyValuePair pair in _consumers) + lock (_consumers) { - ShutdownConsumer(pair.Value, reason); + return _consumers.Remove(tag, out var consumer) ? consumer : GetDefaultOrFallbackConsumer(); } - _consumers.Clear(); } - return InternalShutdownAsync(); - } + public Task ShutdownAsync(ShutdownEventArgs reason) + { + lock (_consumers) + { + foreach (KeyValuePair pair in _consumers) + { + ShutdownConsumer(pair.Value, reason); + } + _consumers.Clear(); + } - protected abstract void ShutdownConsumer(IBasicConsumer consumer, ShutdownEventArgs reason); + return InternalShutdownAsync(); + } - protected abstract Task InternalShutdownAsync(); + protected abstract void ShutdownConsumer(IBasicConsumer consumer, ShutdownEventArgs reason); - // Do not inline as it's not the default case on a hot path - [MethodImpl(MethodImplOptions.NoInlining)] - private IBasicConsumer GetDefaultOrFallbackConsumer() - { - return DefaultConsumer ?? fallbackConsumer; + protected abstract Task InternalShutdownAsync(); + + // Do not inline as it's not the default case on a hot path + [MethodImpl(MethodImplOptions.NoInlining)] + private IBasicConsumer GetDefaultOrFallbackConsumer() + { + return DefaultConsumer ?? fallbackConsumer; + } } } diff --git a/projects/RabbitMQ.Client/client/impl/ConsumerDispatching/ConsumerDispatcherChannelBase.cs b/projects/RabbitMQ.Client/client/impl/ConsumerDispatching/ConsumerDispatcherChannelBase.cs index 3e9925974c..ff5d3535f4 100644 --- a/projects/RabbitMQ.Client/client/impl/ConsumerDispatching/ConsumerDispatcherChannelBase.cs +++ b/projects/RabbitMQ.Client/client/impl/ConsumerDispatching/ConsumerDispatcherChannelBase.cs @@ -4,157 +4,158 @@ using RabbitMQ.Client.Impl; -namespace RabbitMQ.Client.ConsumerDispatching; - -#nullable enable -internal abstract class ConsumerDispatcherChannelBase : ConsumerDispatcherBase, IConsumerDispatcher +namespace RabbitMQ.Client.ConsumerDispatching { - protected readonly ModelBase _model; - protected readonly ChannelReader _reader; - private readonly ChannelWriter _writer; - private readonly Task _worker; +#nullable enable + internal abstract class ConsumerDispatcherChannelBase : ConsumerDispatcherBase, IConsumerDispatcher + { + protected readonly ModelBase _model; + protected readonly ChannelReader _reader; + private readonly ChannelWriter _writer; + private readonly Task _worker; - public bool IsShutdown { get; private set; } + public bool IsShutdown { get; private set; } - protected ConsumerDispatcherChannelBase(ModelBase model, int concurrency) - { - _model = model; - var channel = Channel.CreateUnbounded(new UnboundedChannelOptions - { - SingleReader = concurrency == 1, - SingleWriter = false, - AllowSynchronousContinuations = false - }); - _reader = channel.Reader; - _writer = channel.Writer; - - Func loopStart = ProcessChannelAsync; - if (concurrency == 1) + protected ConsumerDispatcherChannelBase(ModelBase model, int concurrency) { - _worker = Task.Run(loopStart); + _model = model; + var channel = Channel.CreateUnbounded(new UnboundedChannelOptions + { + SingleReader = concurrency == 1, + SingleWriter = false, + AllowSynchronousContinuations = false + }); + _reader = channel.Reader; + _writer = channel.Writer; + + Func loopStart = ProcessChannelAsync; + if (concurrency == 1) + { + _worker = Task.Run(loopStart); + } + else + { + var tasks = new Task[concurrency]; + for (int i = 0; i < concurrency; i++) + { + tasks[i] = Task.Run(loopStart); + } + _worker = Task.WhenAll(tasks); + } } - else + + public void HandleBasicConsumeOk(IBasicConsumer consumer, string consumerTag) { - var tasks = new Task[concurrency]; - for (int i = 0; i < concurrency; i++) + if (!IsShutdown) { - tasks[i] = Task.Run(loopStart); + AddConsumer(consumer, consumerTag); + _writer.TryWrite(new WorkStruct(WorkType.ConsumeOk, consumer, consumerTag)); } - _worker = Task.WhenAll(tasks); } - } - public void HandleBasicConsumeOk(IBasicConsumer consumer, string consumerTag) - { - if (!IsShutdown) + public void HandleBasicDeliver(string consumerTag, ulong deliveryTag, bool redelivered, + string exchange, string routingKey, in ReadOnlyBasicProperties basicProperties, ReadOnlyMemory body, byte[] rentedArray) { - AddConsumer(consumer, consumerTag); - _writer.TryWrite(new WorkStruct(WorkType.ConsumeOk, consumer, consumerTag)); + if (!IsShutdown) + { + _writer.TryWrite(new WorkStruct(GetConsumerOrDefault(consumerTag), consumerTag, deliveryTag, redelivered, exchange, routingKey, basicProperties, body, rentedArray)); + } } - } - public void HandleBasicDeliver(string consumerTag, ulong deliveryTag, bool redelivered, - string exchange, string routingKey, in ReadOnlyBasicProperties basicProperties, ReadOnlyMemory body, byte[] rentedArray) - { - if (!IsShutdown) + public void HandleBasicCancelOk(string consumerTag) { - _writer.TryWrite(new WorkStruct(GetConsumerOrDefault(consumerTag), consumerTag, deliveryTag, redelivered, exchange, routingKey, basicProperties, body, rentedArray)); + if (!IsShutdown) + { + _writer.TryWrite(new WorkStruct(WorkType.CancelOk, GetAndRemoveConsumer(consumerTag), consumerTag)); + } } - } - public void HandleBasicCancelOk(string consumerTag) - { - if (!IsShutdown) + public void HandleBasicCancel(string consumerTag) { - _writer.TryWrite(new WorkStruct(WorkType.CancelOk, GetAndRemoveConsumer(consumerTag), consumerTag)); + if (!IsShutdown) + { + _writer.TryWrite(new WorkStruct(WorkType.Cancel, GetAndRemoveConsumer(consumerTag), consumerTag)); + } } - } - public void HandleBasicCancel(string consumerTag) - { - if (!IsShutdown) + protected sealed override void ShutdownConsumer(IBasicConsumer consumer, ShutdownEventArgs reason) { - _writer.TryWrite(new WorkStruct(WorkType.Cancel, GetAndRemoveConsumer(consumerTag), consumerTag)); + _writer.TryWrite(new WorkStruct(consumer, reason)); } - } - protected sealed override void ShutdownConsumer(IBasicConsumer consumer, ShutdownEventArgs reason) - { - _writer.TryWrite(new WorkStruct(consumer, reason)); - } - - public void Quiesce() - { - IsShutdown = true; - } - - protected override Task InternalShutdownAsync() - { - _writer.Complete(); - return _worker; - } - - public Task WaitForShutdownAsync() - { - return _worker; - } - - protected abstract Task ProcessChannelAsync(); + public void Quiesce() + { + IsShutdown = true; + } - protected readonly struct WorkStruct - { - public readonly IBasicConsumer Consumer; - public IAsyncBasicConsumer AsyncConsumer => (IAsyncBasicConsumer)Consumer; - public readonly string? ConsumerTag; - public readonly ulong DeliveryTag; - public readonly bool Redelivered; - public readonly string? Exchange; - public readonly string? RoutingKey; - public readonly ReadOnlyBasicProperties BasicProperties; - public readonly ReadOnlyMemory Body; - public readonly byte[]? RentedArray; - public readonly ShutdownEventArgs? Reason; - public readonly WorkType WorkType; - - public WorkStruct(WorkType type, IBasicConsumer consumer, string consumerTag) - : this() + protected override Task InternalShutdownAsync() { - WorkType = type; - Consumer = consumer; - ConsumerTag = consumerTag; + _writer.Complete(); + return _worker; } - public WorkStruct(IBasicConsumer consumer, ShutdownEventArgs reason) - : this() + public Task WaitForShutdownAsync() { - WorkType = WorkType.Shutdown; - Consumer = consumer; - Reason = reason; + return _worker; } - public WorkStruct(IBasicConsumer consumer, string consumerTag, ulong deliveryTag, bool redelivered, - string exchange, string routingKey, in ReadOnlyBasicProperties basicProperties, ReadOnlyMemory body, byte[] rentedArray) + protected abstract Task ProcessChannelAsync(); + + protected readonly struct WorkStruct { - WorkType = WorkType.Deliver; - Consumer = consumer; - ConsumerTag = consumerTag; - DeliveryTag = deliveryTag; - Redelivered = redelivered; - Exchange = exchange; - RoutingKey = routingKey; - BasicProperties = basicProperties; - Body = body; - RentedArray = rentedArray; - Reason = default; + public readonly IBasicConsumer Consumer; + public IAsyncBasicConsumer AsyncConsumer => (IAsyncBasicConsumer)Consumer; + public readonly string? ConsumerTag; + public readonly ulong DeliveryTag; + public readonly bool Redelivered; + public readonly string? Exchange; + public readonly string? RoutingKey; + public readonly ReadOnlyBasicProperties BasicProperties; + public readonly ReadOnlyMemory Body; + public readonly byte[]? RentedArray; + public readonly ShutdownEventArgs? Reason; + public readonly WorkType WorkType; + + public WorkStruct(WorkType type, IBasicConsumer consumer, string consumerTag) + : this() + { + WorkType = type; + Consumer = consumer; + ConsumerTag = consumerTag; + } + + public WorkStruct(IBasicConsumer consumer, ShutdownEventArgs reason) + : this() + { + WorkType = WorkType.Shutdown; + Consumer = consumer; + Reason = reason; + } + + public WorkStruct(IBasicConsumer consumer, string consumerTag, ulong deliveryTag, bool redelivered, + string exchange, string routingKey, in ReadOnlyBasicProperties basicProperties, ReadOnlyMemory body, byte[] rentedArray) + { + WorkType = WorkType.Deliver; + Consumer = consumer; + ConsumerTag = consumerTag; + DeliveryTag = deliveryTag; + Redelivered = redelivered; + Exchange = exchange; + RoutingKey = routingKey; + BasicProperties = basicProperties; + Body = body; + RentedArray = rentedArray; + Reason = default; + } } - } - protected enum WorkType : byte - { - Shutdown, - Cancel, - CancelOk, - Deliver, - ConsumeOk + protected enum WorkType : byte + { + Shutdown, + Cancel, + CancelOk, + Deliver, + ConsumeOk + } } } diff --git a/projects/RabbitMQ.Client/client/impl/ConsumerDispatching/FallbackConsumer.cs b/projects/RabbitMQ.Client/client/impl/ConsumerDispatching/FallbackConsumer.cs index 7cffb28b2b..866cba8069 100644 --- a/projects/RabbitMQ.Client/client/impl/ConsumerDispatching/FallbackConsumer.cs +++ b/projects/RabbitMQ.Client/client/impl/ConsumerDispatching/FallbackConsumer.cs @@ -3,79 +3,80 @@ using RabbitMQ.Client.Events; using RabbitMQ.Client.Logging; -namespace RabbitMQ.Client.ConsumerDispatching; - -#nullable enable -internal sealed class FallbackConsumer : IBasicConsumer, IAsyncBasicConsumer +namespace RabbitMQ.Client.ConsumerDispatching { - public IModel? Model { get; } = null; - - event AsyncEventHandler IAsyncBasicConsumer.ConsumerCancelled +#nullable enable + internal sealed class FallbackConsumer : IBasicConsumer, IAsyncBasicConsumer { - add { } - remove { } - } + public IModel? Model { get; } = null; - event EventHandler IBasicConsumer.ConsumerCancelled - { - add { } - remove { } - } + event AsyncEventHandler IAsyncBasicConsumer.ConsumerCancelled + { + add { } + remove { } + } - void IBasicConsumer.HandleBasicCancel(string consumerTag) - { - ESLog.Info($"Unhandled {nameof(IBasicConsumer.HandleBasicCancel)} for tag {consumerTag}"); - } + event EventHandler IBasicConsumer.ConsumerCancelled + { + add { } + remove { } + } - void IBasicConsumer.HandleBasicCancelOk(string consumerTag) - { - ESLog.Info($"Unhandled {nameof(IBasicConsumer.HandleBasicCancelOk)} for tag {consumerTag}"); - } + void IBasicConsumer.HandleBasicCancel(string consumerTag) + { + ESLog.Info($"Unhandled {nameof(IBasicConsumer.HandleBasicCancel)} for tag {consumerTag}"); + } - void IBasicConsumer.HandleBasicConsumeOk(string consumerTag) - { - ESLog.Info($"Unhandled {nameof(IBasicConsumer.HandleBasicConsumeOk)} for tag {consumerTag}"); - } + void IBasicConsumer.HandleBasicCancelOk(string consumerTag) + { + ESLog.Info($"Unhandled {nameof(IBasicConsumer.HandleBasicCancelOk)} for tag {consumerTag}"); + } - void IBasicConsumer.HandleBasicDeliver(string consumerTag, ulong deliveryTag, bool redelivered, string exchange, string routingKey, in ReadOnlyBasicProperties properties, - ReadOnlyMemory body) - { - ESLog.Info($"Unhandled {nameof(IBasicConsumer.HandleBasicDeliver)} for tag {consumerTag}"); - } + void IBasicConsumer.HandleBasicConsumeOk(string consumerTag) + { + ESLog.Info($"Unhandled {nameof(IBasicConsumer.HandleBasicConsumeOk)} for tag {consumerTag}"); + } - void IBasicConsumer.HandleModelShutdown(object model, ShutdownEventArgs reason) - { - ESLog.Info($"Unhandled {nameof(IBasicConsumer.HandleModelShutdown)}"); - } + void IBasicConsumer.HandleBasicDeliver(string consumerTag, ulong deliveryTag, bool redelivered, string exchange, string routingKey, in ReadOnlyBasicProperties properties, + ReadOnlyMemory body) + { + ESLog.Info($"Unhandled {nameof(IBasicConsumer.HandleBasicDeliver)} for tag {consumerTag}"); + } - Task IAsyncBasicConsumer.HandleBasicCancel(string consumerTag) - { - ((IBasicConsumer)this).HandleBasicCancel(consumerTag); - return Task.CompletedTask; - } + void IBasicConsumer.HandleModelShutdown(object model, ShutdownEventArgs reason) + { + ESLog.Info($"Unhandled {nameof(IBasicConsumer.HandleModelShutdown)}"); + } - Task IAsyncBasicConsumer.HandleBasicCancelOk(string consumerTag) - { - ((IBasicConsumer)this).HandleBasicCancelOk(consumerTag); - return Task.CompletedTask; - } + Task IAsyncBasicConsumer.HandleBasicCancel(string consumerTag) + { + ((IBasicConsumer)this).HandleBasicCancel(consumerTag); + return Task.CompletedTask; + } - Task IAsyncBasicConsumer.HandleBasicConsumeOk(string consumerTag) - { - ((IBasicConsumer)this).HandleBasicConsumeOk(consumerTag); - return Task.CompletedTask; - } + Task IAsyncBasicConsumer.HandleBasicCancelOk(string consumerTag) + { + ((IBasicConsumer)this).HandleBasicCancelOk(consumerTag); + return Task.CompletedTask; + } - Task IAsyncBasicConsumer.HandleBasicDeliver(string consumerTag, ulong deliveryTag, bool redelivered, string exchange, string routingKey, in ReadOnlyBasicProperties properties, - ReadOnlyMemory body) - { - ((IBasicConsumer)this).HandleBasicDeliver(consumerTag, deliveryTag, redelivered, exchange, routingKey, properties, body); - return Task.CompletedTask; - } + Task IAsyncBasicConsumer.HandleBasicConsumeOk(string consumerTag) + { + ((IBasicConsumer)this).HandleBasicConsumeOk(consumerTag); + return Task.CompletedTask; + } - Task IAsyncBasicConsumer.HandleModelShutdown(object model, ShutdownEventArgs reason) - { - ((IBasicConsumer)this).HandleModelShutdown(model, reason); - return Task.CompletedTask; + Task IAsyncBasicConsumer.HandleBasicDeliver(string consumerTag, ulong deliveryTag, bool redelivered, string exchange, string routingKey, in ReadOnlyBasicProperties properties, + ReadOnlyMemory body) + { + ((IBasicConsumer)this).HandleBasicDeliver(consumerTag, deliveryTag, redelivered, exchange, routingKey, properties, body); + return Task.CompletedTask; + } + + Task IAsyncBasicConsumer.HandleModelShutdown(object model, ShutdownEventArgs reason) + { + ((IBasicConsumer)this).HandleModelShutdown(model, reason); + return Task.CompletedTask; + } } } diff --git a/projects/RabbitMQ.Client/client/impl/ConsumerDispatching/IConsumerDispatcher.cs b/projects/RabbitMQ.Client/client/impl/ConsumerDispatching/IConsumerDispatcher.cs index 7f3a3c3d8f..ba7c462529 100644 --- a/projects/RabbitMQ.Client/client/impl/ConsumerDispatching/IConsumerDispatcher.cs +++ b/projects/RabbitMQ.Client/client/impl/ConsumerDispatching/IConsumerDispatcher.cs @@ -32,35 +32,36 @@ using System; using System.Threading.Tasks; -namespace RabbitMQ.Client.ConsumerDispatching; - -#nullable enable -internal interface IConsumerDispatcher +namespace RabbitMQ.Client.ConsumerDispatching { - IBasicConsumer? DefaultConsumer { get; set; } +#nullable enable + internal interface IConsumerDispatcher + { + IBasicConsumer? DefaultConsumer { get; set; } - bool IsShutdown { get; } + bool IsShutdown { get; } - IBasicConsumer GetAndRemoveConsumer(string tag); + IBasicConsumer GetAndRemoveConsumer(string tag); - void HandleBasicConsumeOk(IBasicConsumer consumer, string consumerTag); + void HandleBasicConsumeOk(IBasicConsumer consumer, string consumerTag); - void HandleBasicDeliver(string consumerTag, - ulong deliveryTag, - bool redelivered, - string exchange, - string routingKey, - in ReadOnlyBasicProperties basicProperties, - ReadOnlyMemory body, - byte[] rentedArray); + void HandleBasicDeliver(string consumerTag, + ulong deliveryTag, + bool redelivered, + string exchange, + string routingKey, + in ReadOnlyBasicProperties basicProperties, + ReadOnlyMemory body, + byte[] rentedArray); - void HandleBasicCancelOk(string consumerTag); + void HandleBasicCancelOk(string consumerTag); - void HandleBasicCancel(string consumerTag); + void HandleBasicCancel(string consumerTag); - void Quiesce(); + void Quiesce(); - Task ShutdownAsync(ShutdownEventArgs reason); + Task ShutdownAsync(ShutdownEventArgs reason); - Task WaitForShutdownAsync(); + Task WaitForShutdownAsync(); + } } diff --git a/projects/RabbitMQ.Client/client/impl/EmptyBasicProperty.cs b/projects/RabbitMQ.Client/client/impl/EmptyBasicProperty.cs index a1276bbc8c..f1a3459bc3 100644 --- a/projects/RabbitMQ.Client/client/impl/EmptyBasicProperty.cs +++ b/projects/RabbitMQ.Client/client/impl/EmptyBasicProperty.cs @@ -3,54 +3,55 @@ using RabbitMQ.Client.Framing.Impl; using RabbitMQ.Client.Impl; -namespace RabbitMQ.Client.client.impl; - -#nullable enable -internal readonly struct EmptyBasicProperty : IReadOnlyBasicProperties, IAmqpHeader +namespace RabbitMQ.Client.client.impl { - internal static EmptyBasicProperty Empty; +#nullable enable + internal readonly struct EmptyBasicProperty : IReadOnlyBasicProperties, IAmqpHeader + { + internal static EmptyBasicProperty Empty; - ushort IAmqpHeader.ProtocolClassId => ClassConstants.Basic; + ushort IAmqpHeader.ProtocolClassId => ClassConstants.Basic; - int IAmqpWriteable.WriteTo(Span span) - { - return WireFormatting.WriteShort(ref span.GetStart(), 0); - } + int IAmqpWriteable.WriteTo(Span span) + { + return WireFormatting.WriteShort(ref span.GetStart(), 0); + } - int IAmqpWriteable.GetRequiredBufferSize() - { - return 2; // number of presence fields (14) in 2 bytes blocks - } + int IAmqpWriteable.GetRequiredBufferSize() + { + return 2; // number of presence fields (14) in 2 bytes blocks + } - public string? AppId => default; - public string? ClusterId => default; - public string? ContentEncoding => default; - public string? ContentType => default; - public string? CorrelationId => default; - public DeliveryModes DeliveryMode => default; - public string? Expiration => default; - public IDictionary? Headers => default; - public string? MessageId => default; - public bool Persistent => default; - public byte Priority => default; - public string? ReplyTo => default; - public PublicationAddress? ReplyToAddress => default; - public AmqpTimestamp Timestamp => default; - public string? Type => default; - public string? UserId => default; + public string? AppId => default; + public string? ClusterId => default; + public string? ContentEncoding => default; + public string? ContentType => default; + public string? CorrelationId => default; + public DeliveryModes DeliveryMode => default; + public string? Expiration => default; + public IDictionary? Headers => default; + public string? MessageId => default; + public bool Persistent => default; + public byte Priority => default; + public string? ReplyTo => default; + public PublicationAddress? ReplyToAddress => default; + public AmqpTimestamp Timestamp => default; + public string? Type => default; + public string? UserId => default; - public bool IsAppIdPresent() => false; - public bool IsClusterIdPresent() => false; - public bool IsContentEncodingPresent() => false; - public bool IsContentTypePresent() => false; - public bool IsCorrelationIdPresent() => false; - public bool IsDeliveryModePresent() => false; - public bool IsExpirationPresent() => false; - public bool IsHeadersPresent() => false; - public bool IsMessageIdPresent() => false; - public bool IsPriorityPresent() => false; - public bool IsReplyToPresent() => false; - public bool IsTimestampPresent() => false; - public bool IsTypePresent() => false; - public bool IsUserIdPresent() => false; + public bool IsAppIdPresent() => false; + public bool IsClusterIdPresent() => false; + public bool IsContentEncodingPresent() => false; + public bool IsContentTypePresent() => false; + public bool IsCorrelationIdPresent() => false; + public bool IsDeliveryModePresent() => false; + public bool IsExpirationPresent() => false; + public bool IsHeadersPresent() => false; + public bool IsMessageIdPresent() => false; + public bool IsPriorityPresent() => false; + public bool IsReplyToPresent() => false; + public bool IsTimestampPresent() => false; + public bool IsTypePresent() => false; + public bool IsUserIdPresent() => false; + } } diff --git a/projects/RabbitMQ.Client/client/impl/EventingWrapper.cs b/projects/RabbitMQ.Client/client/impl/EventingWrapper.cs index 8970e38ca8..2395c3ce73 100644 --- a/projects/RabbitMQ.Client/client/impl/EventingWrapper.cs +++ b/projects/RabbitMQ.Client/client/impl/EventingWrapper.cs @@ -2,139 +2,140 @@ using System.Threading.Tasks; using RabbitMQ.Client.Events; -namespace RabbitMQ.Client.Impl; - -#nullable enable -internal struct EventingWrapper +namespace RabbitMQ.Client.Impl { - private event EventHandler? _event; - private Delegate[]? _handlers; - private string? _context; - private Action? _onExceptionAction; - - public bool IsEmpty => _event is null; - - public EventingWrapper(string context, Action onExceptionAction) +#nullable enable + internal struct EventingWrapper { - _event = null; - _handlers = null; - _context = context; - _onExceptionAction = onExceptionAction; - } + private event EventHandler? _event; + private Delegate[]? _handlers; + private string? _context; + private Action? _onExceptionAction; - public void AddHandler(EventHandler? handler) - { - _event += handler; - _handlers = null; - } + public bool IsEmpty => _event is null; - public void RemoveHandler(EventHandler? handler) - { - _event -= handler; - _handlers = null; - } + public EventingWrapper(string context, Action onExceptionAction) + { + _event = null; + _handlers = null; + _context = context; + _onExceptionAction = onExceptionAction; + } - public void ClearHandlers() - { - _event = null; - _handlers = null; - } + public void AddHandler(EventHandler? handler) + { + _event += handler; + _handlers = null; + } - public void Invoke(object sender, T parameter) - { - var handlers = _handlers; - if (handlers is null) + public void RemoveHandler(EventHandler? handler) { - handlers = _event?.GetInvocationList(); - if (handlers is null) - { - return; - } + _event -= handler; + _handlers = null; + } - _handlers = handlers; + public void ClearHandlers() + { + _event = null; + _handlers = null; } - foreach (EventHandler action in handlers) + + public void Invoke(object sender, T parameter) { - try + var handlers = _handlers; + if (handlers is null) { - action(sender, parameter); + handlers = _event?.GetInvocationList(); + if (handlers is null) + { + return; + } + + _handlers = handlers; } - catch (Exception exception) + foreach (EventHandler action in handlers) { - var onException = _onExceptionAction; - if (onException != null) + try { - onException(exception, _context!); + action(sender, parameter); } - else + catch (Exception exception) { - throw; + var onException = _onExceptionAction; + if (onException != null) + { + onException(exception, _context!); + } + else + { + throw; + } } } } - } - public void Takeover(in EventingWrapper other) - { - _event = other._event; - _handlers = other._handlers; - _context = other._context; - _onExceptionAction = other._onExceptionAction; + public void Takeover(in EventingWrapper other) + { + _event = other._event; + _handlers = other._handlers; + _context = other._context; + _onExceptionAction = other._onExceptionAction; + } } -} -internal struct AsyncEventingWrapper -{ - private event AsyncEventHandler? _event; - private Delegate[]? _handlers; + internal struct AsyncEventingWrapper + { + private event AsyncEventHandler? _event; + private Delegate[]? _handlers; - public bool IsEmpty => _event is null; + public bool IsEmpty => _event is null; - public void AddHandler(AsyncEventHandler? handler) - { - _event += handler; - _handlers = null; - } + public void AddHandler(AsyncEventHandler? handler) + { + _event += handler; + _handlers = null; + } - public void RemoveHandler(AsyncEventHandler? handler) - { - _event -= handler; - _handlers = null; - } + public void RemoveHandler(AsyncEventHandler? handler) + { + _event -= handler; + _handlers = null; + } - // Do not make this function async! (This type is a struct that gets copied at the start of an async method => empty _handlers is copied) - public Task InvokeAsync(object sender, T parameter) - { - var handlers = _handlers; - if (handlers is null) + // Do not make this function async! (This type is a struct that gets copied at the start of an async method => empty _handlers is copied) + public Task InvokeAsync(object sender, T parameter) { - handlers = _event?.GetInvocationList(); + var handlers = _handlers; if (handlers is null) { - return Task.CompletedTask; + handlers = _event?.GetInvocationList(); + if (handlers is null) + { + return Task.CompletedTask; + } + + _handlers = handlers; } - _handlers = handlers; + if (handlers.Length == 1) + { + return ((AsyncEventHandler)handlers[0])(sender, parameter); + } + return InternalInvoke(handlers, sender, parameter); } - if (handlers.Length == 1) + private static async Task InternalInvoke(Delegate[] handlers, object sender, T parameter) { - return ((AsyncEventHandler)handlers[0])(sender, parameter); + foreach (AsyncEventHandler action in handlers) + { + await action(sender, parameter).ConfigureAwait(false); + } } - return InternalInvoke(handlers, sender, parameter); - } - private static async Task InternalInvoke(Delegate[] handlers, object sender, T parameter) - { - foreach (AsyncEventHandler action in handlers) + public void Takeover(in AsyncEventingWrapper other) { - await action(sender, parameter).ConfigureAwait(false); + _event = other._event; + _handlers = other._handlers; } } - - public void Takeover(in AsyncEventingWrapper other) - { - _event = other._event; - _handlers = other._handlers; - } } diff --git a/projects/RabbitMQ.Client/client/impl/Frame.cs b/projects/RabbitMQ.Client/client/impl/Frame.cs index c96ce1340b..b7fe64a680 100644 --- a/projects/RabbitMQ.Client/client/impl/Frame.cs +++ b/projects/RabbitMQ.Client/client/impl/Frame.cs @@ -41,310 +41,311 @@ using RabbitMQ.Client.Logging; using RabbitMQ.Util; -namespace RabbitMQ.Client.Impl; - -internal static class Framing +namespace RabbitMQ.Client.Impl { - /* +------------+---------+----------------+---------+------------------+ - * | Frame Type | Channel | Payload length | Payload | Frame End Marker | - * +------------+---------+----------------+---------+------------------+ - * | 1 byte | 2 bytes | 4 bytes | x bytes | 1 byte | - * +------------+---------+----------------+---------+------------------+ */ - internal const int BaseFrameSize = 1 + 2 + 4 + 1; - private const int StartPayload = 7; - - internal static class Method + internal static class Framing { - /* +----------+-----------+-----------+ - * | CommandId (combined) | Arguments | - * | Class Id | Method Id | | - * +----------+-----------+-----------+ - * | 4 bytes (combined) | x bytes | - * | 2 bytes | 2 bytes | | - * +----------+-----------+-----------+ */ - public const int FrameSize = BaseFrameSize + 2 + 2; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int WriteTo(Span span, ushort channel, ref T method) where T : struct, IOutgoingAmqpMethod + /* +------------+---------+----------------+---------+------------------+ + * | Frame Type | Channel | Payload length | Payload | Frame End Marker | + * +------------+---------+----------------+---------+------------------+ + * | 1 byte | 2 bytes | 4 bytes | x bytes | 1 byte | + * +------------+---------+----------------+---------+------------------+ */ + internal const int BaseFrameSize = 1 + 2 + 4 + 1; + private const int StartPayload = 7; + + internal static class Method { - const int StartClassId = StartPayload; - const int StartMethodArguments = StartClassId + 4; - - int payloadLength = method.WriteTo(span.Slice(StartMethodArguments)) + 4; - NetworkOrderSerializer.WriteUInt64(ref span.GetStart(), ((ulong)Constants.FrameMethod << 56) | ((ulong)channel << 40) | ((ulong)payloadLength << 8)); - NetworkOrderSerializer.WriteUInt32(ref span.GetOffset(StartClassId), (uint)method.ProtocolCommandId); - span[payloadLength + StartPayload] = Constants.FrameEnd; - return payloadLength + BaseFrameSize; + /* +----------+-----------+-----------+ + * | CommandId (combined) | Arguments | + * | Class Id | Method Id | | + * +----------+-----------+-----------+ + * | 4 bytes (combined) | x bytes | + * | 2 bytes | 2 bytes | | + * +----------+-----------+-----------+ */ + public const int FrameSize = BaseFrameSize + 2 + 2; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int WriteTo(Span span, ushort channel, ref T method) where T : struct, IOutgoingAmqpMethod + { + const int StartClassId = StartPayload; + const int StartMethodArguments = StartClassId + 4; + + int payloadLength = method.WriteTo(span.Slice(StartMethodArguments)) + 4; + NetworkOrderSerializer.WriteUInt64(ref span.GetStart(), ((ulong)Constants.FrameMethod << 56) | ((ulong)channel << 40) | ((ulong)payloadLength << 8)); + NetworkOrderSerializer.WriteUInt32(ref span.GetOffset(StartClassId), (uint)method.ProtocolCommandId); + span[payloadLength + StartPayload] = Constants.FrameEnd; + return payloadLength + BaseFrameSize; + } } - } - internal static class Header - { - /* +----------+----------+-------------------+-----------+ - * | Class Id | (unused) | Total body length | Arguments | - * +----------+----------+-------------------+-----------+ - * | 2 bytes | 2 bytes | 8 bytes | x bytes | - * +----------+----------+-------------------+-----------+ */ - public const int FrameSize = BaseFrameSize + 2 + 2 + 8; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int WriteTo(Span span, ushort channel, ref T header, int bodyLength) where T : IAmqpHeader + internal static class Header { - const int StartClassId = StartPayload; - const int StartBodyLength = StartPayload + 4; - const int StartHeaderArguments = StartPayload + 12; - - int payloadLength = 12 + header.WriteTo(span.Slice(StartHeaderArguments)); - NetworkOrderSerializer.WriteUInt64(ref span.GetStart(), ((ulong)Constants.FrameHeader << 56) | ((ulong)channel << 40) | ((ulong)payloadLength << 8)); - NetworkOrderSerializer.WriteUInt32(ref span.GetOffset(StartClassId), (uint)header.ProtocolClassId << 16); // The last 16 bytes (Weight) aren't used - NetworkOrderSerializer.WriteUInt64(ref span.GetOffset(StartBodyLength), (ulong)bodyLength); - span[payloadLength + StartPayload] = Constants.FrameEnd; - return payloadLength + BaseFrameSize; + /* +----------+----------+-------------------+-----------+ + * | Class Id | (unused) | Total body length | Arguments | + * +----------+----------+-------------------+-----------+ + * | 2 bytes | 2 bytes | 8 bytes | x bytes | + * +----------+----------+-------------------+-----------+ */ + public const int FrameSize = BaseFrameSize + 2 + 2 + 8; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int WriteTo(Span span, ushort channel, ref T header, int bodyLength) where T : IAmqpHeader + { + const int StartClassId = StartPayload; + const int StartBodyLength = StartPayload + 4; + const int StartHeaderArguments = StartPayload + 12; + + int payloadLength = 12 + header.WriteTo(span.Slice(StartHeaderArguments)); + NetworkOrderSerializer.WriteUInt64(ref span.GetStart(), ((ulong)Constants.FrameHeader << 56) | ((ulong)channel << 40) | ((ulong)payloadLength << 8)); + NetworkOrderSerializer.WriteUInt32(ref span.GetOffset(StartClassId), (uint)header.ProtocolClassId << 16); // The last 16 bytes (Weight) aren't used + NetworkOrderSerializer.WriteUInt64(ref span.GetOffset(StartBodyLength), (ulong)bodyLength); + span[payloadLength + StartPayload] = Constants.FrameEnd; + return payloadLength + BaseFrameSize; + } } - } - internal static class BodySegment - { - /* +--------------+ - * | Body segment | - * +--------------+ - * | x bytes | - * +--------------+ */ - public const int FrameSize = BaseFrameSize; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int WriteTo(Span span, ushort channel, ReadOnlySpan body) + internal static class BodySegment { - const int StartBodyArgument = StartPayload; - NetworkOrderSerializer.WriteUInt64(ref span.GetStart(), ((ulong)Constants.FrameBody << 56) | ((ulong)channel << 40) | ((ulong)body.Length << 8)); - body.CopyTo(span.Slice(StartBodyArgument)); - span[StartPayload + body.Length] = Constants.FrameEnd; - return body.Length + BaseFrameSize; + /* +--------------+ + * | Body segment | + * +--------------+ + * | x bytes | + * +--------------+ */ + public const int FrameSize = BaseFrameSize; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int WriteTo(Span span, ushort channel, ReadOnlySpan body) + { + const int StartBodyArgument = StartPayload; + NetworkOrderSerializer.WriteUInt64(ref span.GetStart(), ((ulong)Constants.FrameBody << 56) | ((ulong)channel << 40) | ((ulong)body.Length << 8)); + body.CopyTo(span.Slice(StartBodyArgument)); + span[StartPayload + body.Length] = Constants.FrameEnd; + return body.Length + BaseFrameSize; + } } - } - internal static class Heartbeat - { - /* Empty frame */ - public const int FrameSize = BaseFrameSize; - - /// - /// Compiler trick to directly refer to static data in the assembly, see here: https://github.com/dotnet/roslyn/pull/24621 - /// - private static ReadOnlySpan Payload => new byte[] - { - Constants.FrameHeartbeat, - 0, 0, // channel - 0, 0, 0, 0, // payload length - Constants.FrameEnd - }; - - public static Memory GetHeartbeatFrame() + internal static class Heartbeat { - // Is returned by SocketFrameHandler.WriteLoop - byte[] buffer = ArrayPool.Shared.Rent(FrameSize); - Payload.CopyTo(buffer); - return new Memory(buffer, 0, FrameSize); - } - } + /* Empty frame */ + public const int FrameSize = BaseFrameSize; - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ReadOnlyMemory SerializeToFrames(ref T method, ushort channelNumber) - where T : struct, IOutgoingAmqpMethod - { - int size = Method.FrameSize + method.GetRequiredBufferSize(); - - // Will be returned by SocketFrameWriter.WriteLoop - var array = ArrayPool.Shared.Rent(size); - int offset = Method.WriteTo(array, channelNumber, ref method); - - System.Diagnostics.Debug.Assert(offset == size, $"Serialized to wrong size, expect {size}, offset {offset}"); - return new ReadOnlyMemory(array, 0, size); - } + /// + /// Compiler trick to directly refer to static data in the assembly, see here: https://github.com/dotnet/roslyn/pull/24621 + /// + private static ReadOnlySpan Payload => new byte[] + { + Constants.FrameHeartbeat, + 0, 0, // channel + 0, 0, 0, 0, // payload length + Constants.FrameEnd + }; - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ReadOnlyMemory SerializeToFrames(ref TMethod method, ref THeader header, ReadOnlyMemory body, ushort channelNumber, int maxBodyPayloadBytes) - where TMethod : struct, IOutgoingAmqpMethod - where THeader : IAmqpHeader - { - int remainingBodyBytes = body.Length; - int size = Method.FrameSize + Header.FrameSize + - method.GetRequiredBufferSize() + header.GetRequiredBufferSize() + - BodySegment.FrameSize * GetBodyFrameCount(maxBodyPayloadBytes, remainingBodyBytes) + remainingBodyBytes; - - // Will be returned by SocketFrameWriter.WriteLoop - var array = ArrayPool.Shared.Rent(size); - - int offset = Method.WriteTo(array, channelNumber, ref method); - offset += Header.WriteTo(array.AsSpan(offset), channelNumber, ref header, remainingBodyBytes); - var bodySpan = body.Span; - while (remainingBodyBytes > 0) - { - int frameSize = remainingBodyBytes > maxBodyPayloadBytes ? maxBodyPayloadBytes : remainingBodyBytes; - offset += BodySegment.WriteTo(array.AsSpan(offset), channelNumber, bodySpan.Slice(bodySpan.Length - remainingBodyBytes, frameSize)); - remainingBodyBytes -= frameSize; + public static Memory GetHeartbeatFrame() + { + // Is returned by SocketFrameHandler.WriteLoop + byte[] buffer = ArrayPool.Shared.Rent(FrameSize); + Payload.CopyTo(buffer); + return new Memory(buffer, 0, FrameSize); + } } - System.Diagnostics.Debug.Assert(offset == size, $"Serialized to wrong size, expect {size}, offset {offset}"); - return new ReadOnlyMemory(array, 0, size); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static int GetBodyFrameCount(int maxPayloadBytes, int length) - { - if (maxPayloadBytes == int.MaxValue) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ReadOnlyMemory SerializeToFrames(ref T method, ushort channelNumber) + where T : struct, IOutgoingAmqpMethod { - return 1; - } - - return (length + maxPayloadBytes - 1) / maxPayloadBytes; - } -} + int size = Method.FrameSize + method.GetRequiredBufferSize(); -internal readonly ref struct InboundFrame -{ - public readonly FrameType Type; - public readonly int Channel; - public readonly ReadOnlyMemory Payload; - private readonly byte[] _rentedArray; + // Will be returned by SocketFrameWriter.WriteLoop + var array = ArrayPool.Shared.Rent(size); + int offset = Method.WriteTo(array, channelNumber, ref method); - private InboundFrame(FrameType type, int channel, ReadOnlyMemory payload, byte[] rentedArray) - { - Type = type; - Channel = channel; - Payload = payload; - _rentedArray = rentedArray; - } + System.Diagnostics.Debug.Assert(offset == size, $"Serialized to wrong size, expect {size}, offset {offset}"); + return new ReadOnlyMemory(array, 0, size); + } - private static void ProcessProtocolHeader(Stream reader, ReadOnlySpan frameHeader) - { - try + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ReadOnlyMemory SerializeToFrames(ref TMethod method, ref THeader header, ReadOnlyMemory body, ushort channelNumber, int maxBodyPayloadBytes) + where TMethod : struct, IOutgoingAmqpMethod + where THeader : IAmqpHeader { - if (frameHeader[0] != 'M' || frameHeader[1] != 'Q' || frameHeader[2] != 'P') + int remainingBodyBytes = body.Length; + int size = Method.FrameSize + Header.FrameSize + + method.GetRequiredBufferSize() + header.GetRequiredBufferSize() + + BodySegment.FrameSize * GetBodyFrameCount(maxBodyPayloadBytes, remainingBodyBytes) + remainingBodyBytes; + + // Will be returned by SocketFrameWriter.WriteLoop + var array = ArrayPool.Shared.Rent(size); + + int offset = Method.WriteTo(array, channelNumber, ref method); + offset += Header.WriteTo(array.AsSpan(offset), channelNumber, ref header, remainingBodyBytes); + var bodySpan = body.Span; + while (remainingBodyBytes > 0) { - throw new MalformedFrameException("Invalid AMQP protocol header from server"); + int frameSize = remainingBodyBytes > maxBodyPayloadBytes ? maxBodyPayloadBytes : remainingBodyBytes; + offset += BodySegment.WriteTo(array.AsSpan(offset), channelNumber, bodySpan.Slice(bodySpan.Length - remainingBodyBytes, frameSize)); + remainingBodyBytes -= frameSize; } - int serverMinor = reader.ReadByte(); - if (serverMinor == -1) + System.Diagnostics.Debug.Assert(offset == size, $"Serialized to wrong size, expect {size}, offset {offset}"); + return new ReadOnlyMemory(array, 0, size); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static int GetBodyFrameCount(int maxPayloadBytes, int length) + { + if (maxPayloadBytes == int.MaxValue) { - throw new EndOfStreamException(); + return 1; } - throw new PacketNotRecognizedException(frameHeader[3], frameHeader[4], frameHeader[5], serverMinor); - } - catch (EndOfStreamException) - { - // Ideally we'd wrap the EndOfStreamException in the - // MalformedFrameException, but unfortunately the - // design of MalformedFrameException's superclass, - // ProtocolViolationException, doesn't permit - // this. Fortunately, the call stack in the - // EndOfStreamException is largely irrelevant at this - // point, so can safely be ignored. - throw new MalformedFrameException("Invalid AMQP protocol header from server"); + return (length + maxPayloadBytes - 1) / maxPayloadBytes; } } - internal static InboundFrame ReadFrom(Stream reader, byte[] frameHeaderBuffer) + internal readonly ref struct InboundFrame { - try + public readonly FrameType Type; + public readonly int Channel; + public readonly ReadOnlyMemory Payload; + private readonly byte[] _rentedArray; + + private InboundFrame(FrameType type, int channel, ReadOnlyMemory payload, byte[] rentedArray) { - ReadFromStream(reader, frameHeaderBuffer, frameHeaderBuffer.Length); + Type = type; + Channel = channel; + Payload = payload; + _rentedArray = rentedArray; } - catch (IOException ioe) + + private static void ProcessProtocolHeader(Stream reader, ReadOnlySpan frameHeader) { - // If it's a WSAETIMEDOUT SocketException, unwrap it. - // This might happen when the limit of half-open connections is - // reached. - if (ioe?.InnerException is SocketException exception && exception.SocketErrorCode == SocketError.TimedOut) + try { - ExceptionDispatchInfo.Capture(exception).Throw(); + if (frameHeader[0] != 'M' || frameHeader[1] != 'Q' || frameHeader[2] != 'P') + { + throw new MalformedFrameException("Invalid AMQP protocol header from server"); + } + + int serverMinor = reader.ReadByte(); + if (serverMinor == -1) + { + throw new EndOfStreamException(); + } + + throw new PacketNotRecognizedException(frameHeader[3], frameHeader[4], frameHeader[5], serverMinor); } - else + catch (EndOfStreamException) { - throw; + // Ideally we'd wrap the EndOfStreamException in the + // MalformedFrameException, but unfortunately the + // design of MalformedFrameException's superclass, + // ProtocolViolationException, doesn't permit + // this. Fortunately, the call stack in the + // EndOfStreamException is largely irrelevant at this + // point, so can safely be ignored. + throw new MalformedFrameException("Invalid AMQP protocol header from server"); } } - byte firstByte = frameHeaderBuffer[0]; - if (firstByte == 'A') + internal static InboundFrame ReadFrom(Stream reader, byte[] frameHeaderBuffer) { - // Probably an AMQP protocol header, otherwise meaningless - ProcessProtocolHeader(reader, frameHeaderBuffer.AsSpan(1, 6)); - } + try + { + ReadFromStream(reader, frameHeaderBuffer, frameHeaderBuffer.Length); + } + catch (IOException ioe) + { + // If it's a WSAETIMEDOUT SocketException, unwrap it. + // This might happen when the limit of half-open connections is + // reached. + if (ioe?.InnerException is SocketException exception && exception.SocketErrorCode == SocketError.TimedOut) + { + ExceptionDispatchInfo.Capture(exception).Throw(); + } + else + { + throw; + } + } - FrameType type = (FrameType)firstByte; - var frameHeaderSpan = new ReadOnlySpan(frameHeaderBuffer, 1, 6); - int channel = NetworkOrderDeserializer.ReadUInt16(frameHeaderSpan); - int payloadSize = NetworkOrderDeserializer.ReadInt32(frameHeaderSpan.Slice(2, 4)); // FIXME - throw exn on unreasonable value + byte firstByte = frameHeaderBuffer[0]; + if (firstByte == 'A') + { + // Probably an AMQP protocol header, otherwise meaningless + ProcessProtocolHeader(reader, frameHeaderBuffer.AsSpan(1, 6)); + } - const int EndMarkerLength = 1; - // Is returned by InboundFrame.ReturnPayload in Connection.MainLoopIteration - int readSize = payloadSize + EndMarkerLength; - byte[] payloadBytes = ArrayPool.Shared.Rent(readSize); - try - { - ReadFromStream(reader, payloadBytes, readSize); - } - catch (Exception) - { - // Early EOF. - ArrayPool.Shared.Return(payloadBytes); - throw new MalformedFrameException($"Short frame - expected to read {readSize} bytes"); + FrameType type = (FrameType)firstByte; + var frameHeaderSpan = new ReadOnlySpan(frameHeaderBuffer, 1, 6); + int channel = NetworkOrderDeserializer.ReadUInt16(frameHeaderSpan); + int payloadSize = NetworkOrderDeserializer.ReadInt32(frameHeaderSpan.Slice(2, 4)); // FIXME - throw exn on unreasonable value + + const int EndMarkerLength = 1; + // Is returned by InboundFrame.ReturnPayload in Connection.MainLoopIteration + int readSize = payloadSize + EndMarkerLength; + byte[] payloadBytes = ArrayPool.Shared.Rent(readSize); + try + { + ReadFromStream(reader, payloadBytes, readSize); + } + catch (Exception) + { + // Early EOF. + ArrayPool.Shared.Return(payloadBytes); + throw new MalformedFrameException($"Short frame - expected to read {readSize} bytes"); + } + + if (payloadBytes[payloadSize] != Constants.FrameEnd) + { + ArrayPool.Shared.Return(payloadBytes); + throw new MalformedFrameException($"Bad frame end marker: {payloadBytes[payloadSize]}"); + } + + RabbitMqClientEventSource.Log.DataReceived(payloadSize + Framing.BaseFrameSize); + return new InboundFrame(type, channel, new Memory(payloadBytes, 0, payloadSize), payloadBytes); } - if (payloadBytes[payloadSize] != Constants.FrameEnd) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void ReadFromStream(Stream reader, byte[] buffer, int toRead) { - ArrayPool.Shared.Return(payloadBytes); - throw new MalformedFrameException($"Bad frame end marker: {payloadBytes[payloadSize]}"); - } + int bytesRead = 0; + do + { + int read = reader.Read(buffer, bytesRead, toRead - bytesRead); + if (read == 0) + { + ThrowEndOfStream(); + } - RabbitMqClientEventSource.Log.DataReceived(payloadSize + Framing.BaseFrameSize); - return new InboundFrame(type, channel, new Memory(payloadBytes, 0, payloadSize), payloadBytes); - } + bytesRead += read; + } while (bytesRead != toRead); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void ReadFromStream(Stream reader, byte[] buffer, int toRead) - { - int bytesRead = 0; - do - { - int read = reader.Read(buffer, bytesRead, toRead - bytesRead); - if (read == 0) + static void ThrowEndOfStream() { - ThrowEndOfStream(); + throw new EndOfStreamException("Reached the end of the stream. Possible authentication failure."); } + } - bytesRead += read; - } while (bytesRead != toRead); - - static void ThrowEndOfStream() + public byte[] TakeoverPayload() { - throw new EndOfStreamException("Reached the end of the stream. Possible authentication failure."); + return _rentedArray; } - } - public byte[] TakeoverPayload() - { - return _rentedArray; - } + public void ReturnPayload() + { + ArrayPool.Shared.Return(_rentedArray); + } - public void ReturnPayload() - { - ArrayPool.Shared.Return(_rentedArray); + public override string ToString() + { + return $"(type={Type}, channel={Channel}, {Payload.Length} bytes of payload)"; + } } - public override string ToString() + internal enum FrameType : int { - return $"(type={Type}, channel={Channel}, {Payload.Length} bytes of payload)"; + FrameMethod = Constants.FrameMethod, + FrameHeader = Constants.FrameHeader, + FrameBody = Constants.FrameBody, + FrameHeartbeat = Constants.FrameHeartbeat } } - -internal enum FrameType : int -{ - FrameMethod = Constants.FrameMethod, - FrameHeader = Constants.FrameHeader, - FrameBody = Constants.FrameBody, - FrameHeartbeat = Constants.FrameHeartbeat -} diff --git a/projects/RabbitMQ.Client/client/impl/IFrameHandler.cs b/projects/RabbitMQ.Client/client/impl/IFrameHandler.cs index 7825496f1b..bdb692bd1e 100644 --- a/projects/RabbitMQ.Client/client/impl/IFrameHandler.cs +++ b/projects/RabbitMQ.Client/client/impl/IFrameHandler.cs @@ -32,34 +32,35 @@ using System; using System.Net; -namespace RabbitMQ.Client.Impl; - -internal interface IFrameHandler +namespace RabbitMQ.Client.Impl { - AmqpTcpEndpoint Endpoint { get; } + internal interface IFrameHandler + { + AmqpTcpEndpoint Endpoint { get; } - EndPoint LocalEndPoint { get; } + EndPoint LocalEndPoint { get; } - int LocalPort { get; } + int LocalPort { get; } - EndPoint RemoteEndPoint { get; } + EndPoint RemoteEndPoint { get; } - int RemotePort { get; } + int RemotePort { get; } - ///Socket read timeout. System.Threading.Timeout.InfiniteTimeSpan signals "infinity". - TimeSpan ReadTimeout { set; } + ///Socket read timeout. System.Threading.Timeout.InfiniteTimeSpan signals "infinity". + TimeSpan ReadTimeout { set; } - ///Socket write timeout. System.Threading.Timeout.InfiniteTimeSpan signals "infinity". - TimeSpan WriteTimeout { set; } + ///Socket write timeout. System.Threading.Timeout.InfiniteTimeSpan signals "infinity". + TimeSpan WriteTimeout { set; } - void Close(); + void Close(); - ///Read a frame from the underlying - ///transport. Returns null if the read operation timed out - ///(see Timeout property). - InboundFrame ReadFrame(); + ///Read a frame from the underlying + ///transport. Returns null if the read operation timed out + ///(see Timeout property). + InboundFrame ReadFrame(); - void SendHeader(); + void SendHeader(); - void Write(ReadOnlyMemory memory); + void Write(ReadOnlyMemory memory); + } } diff --git a/projects/RabbitMQ.Client/client/impl/IRpcContinuation.cs b/projects/RabbitMQ.Client/client/impl/IRpcContinuation.cs index 8a6adaf01f..8cc84d66c0 100644 --- a/projects/RabbitMQ.Client/client/impl/IRpcContinuation.cs +++ b/projects/RabbitMQ.Client/client/impl/IRpcContinuation.cs @@ -29,10 +29,11 @@ // Copyright (c) 2007-2020 VMware, Inc. All rights reserved. //--------------------------------------------------------------------------- -namespace RabbitMQ.Client.Impl; - -internal interface IRpcContinuation +namespace RabbitMQ.Client.Impl { - void HandleCommand(in IncomingCommand cmd); - void HandleModelShutdown(ShutdownEventArgs reason); + internal interface IRpcContinuation + { + void HandleCommand(in IncomingCommand cmd); + void HandleModelShutdown(ShutdownEventArgs reason); + } } diff --git a/projects/RabbitMQ.Client/client/impl/ISession.cs b/projects/RabbitMQ.Client/client/impl/ISession.cs index 3cce48dc57..1ad103fe13 100644 --- a/projects/RabbitMQ.Client/client/impl/ISession.cs +++ b/projects/RabbitMQ.Client/client/impl/ISession.cs @@ -32,48 +32,49 @@ using System; using RabbitMQ.Client.Framing.Impl; -namespace RabbitMQ.Client.Impl; - -internal delegate void CommandReceivedAction(in IncomingCommand cmd); - -internal interface ISession +namespace RabbitMQ.Client.Impl { - /// - /// Gets the channel number. - /// - ushort ChannelNumber { get; } + internal delegate void CommandReceivedAction(in IncomingCommand cmd); + + internal interface ISession + { + /// + /// Gets the channel number. + /// + ushort ChannelNumber { get; } - /// - /// Gets the close reason. - /// - ShutdownEventArgs CloseReason { get; } + /// + /// Gets the close reason. + /// + ShutdownEventArgs CloseReason { get; } - /// - /// Single recipient - no need for multiple handlers to be informed of arriving commands. - /// - CommandReceivedAction CommandReceived { get; set; } + /// + /// Single recipient - no need for multiple handlers to be informed of arriving commands. + /// + CommandReceivedAction CommandReceived { get; set; } - /// - /// Gets the connection. - /// - Connection Connection { get; } + /// + /// Gets the connection. + /// + Connection Connection { get; } - /// - /// Gets a value indicating whether this session is open. - /// - bool IsOpen { get; } + /// + /// Gets a value indicating whether this session is open. + /// + bool IsOpen { get; } - /// - /// Multicast session shutdown event. - /// - event EventHandler SessionShutdown; + /// + /// Multicast session shutdown event. + /// + event EventHandler SessionShutdown; - void Close(ShutdownEventArgs reason); - void Close(ShutdownEventArgs reason, bool notify); - bool HandleFrame(in InboundFrame frame); - void Notify(); - void Transmit(ref T cmd) where T : struct, IOutgoingAmqpMethod; - void Transmit(ref TMethod cmd, ref THeader header, ReadOnlyMemory body) - where TMethod : struct, IOutgoingAmqpMethod - where THeader : IAmqpHeader; + void Close(ShutdownEventArgs reason); + void Close(ShutdownEventArgs reason, bool notify); + bool HandleFrame(in InboundFrame frame); + void Notify(); + void Transmit(ref T cmd) where T : struct, IOutgoingAmqpMethod; + void Transmit(ref TMethod cmd, ref THeader header, ReadOnlyMemory body) + where TMethod : struct, IOutgoingAmqpMethod + where THeader : IAmqpHeader; + } } diff --git a/projects/RabbitMQ.Client/client/impl/IncomingCommand.cs b/projects/RabbitMQ.Client/client/impl/IncomingCommand.cs index 34b81949e0..5f3aa7fbb8 100644 --- a/projects/RabbitMQ.Client/client/impl/IncomingCommand.cs +++ b/projects/RabbitMQ.Client/client/impl/IncomingCommand.cs @@ -2,48 +2,49 @@ using System.Buffers; using RabbitMQ.Client.client.framing; -namespace RabbitMQ.Client.Impl; - -internal readonly struct IncomingCommand +namespace RabbitMQ.Client.Impl { - public static readonly IncomingCommand Empty = default; - - public readonly ProtocolCommandId CommandId; - - public readonly ReadOnlyMemory MethodBytes; - private readonly byte[] _rentedMethodBytes; - - public readonly ReadOnlyMemory HeaderBytes; - private readonly byte[] _rentedHeaderArray; - - public readonly ReadOnlyMemory Body; - private readonly byte[] _rentedBodyArray; - - public bool IsEmpty => CommandId is default(ProtocolCommandId); - - public IncomingCommand(ProtocolCommandId commandId, ReadOnlyMemory methodBytes, byte[] rentedMethodArray, ReadOnlyMemory headerBytes, byte[] rentedHeaderArray, ReadOnlyMemory body, byte[] rentedBodyArray) - { - CommandId = commandId; - MethodBytes = methodBytes; - _rentedMethodBytes = rentedMethodArray; - HeaderBytes = headerBytes; - _rentedHeaderArray = rentedHeaderArray; - Body = body; - _rentedBodyArray = rentedBodyArray; - } - - public byte[] TakeoverBody() - { - return _rentedBodyArray; - } - - public void ReturnHeaderBuffer() - { - ArrayPool.Shared.Return(_rentedHeaderArray); - } - - public void ReturnMethodBuffer() + internal readonly struct IncomingCommand { - ArrayPool.Shared.Return(_rentedMethodBytes); + public static readonly IncomingCommand Empty = default; + + public readonly ProtocolCommandId CommandId; + + public readonly ReadOnlyMemory MethodBytes; + private readonly byte[] _rentedMethodBytes; + + public readonly ReadOnlyMemory HeaderBytes; + private readonly byte[] _rentedHeaderArray; + + public readonly ReadOnlyMemory Body; + private readonly byte[] _rentedBodyArray; + + public bool IsEmpty => CommandId is default(ProtocolCommandId); + + public IncomingCommand(ProtocolCommandId commandId, ReadOnlyMemory methodBytes, byte[] rentedMethodArray, ReadOnlyMemory headerBytes, byte[] rentedHeaderArray, ReadOnlyMemory body, byte[] rentedBodyArray) + { + CommandId = commandId; + MethodBytes = methodBytes; + _rentedMethodBytes = rentedMethodArray; + HeaderBytes = headerBytes; + _rentedHeaderArray = rentedHeaderArray; + Body = body; + _rentedBodyArray = rentedBodyArray; + } + + public byte[] TakeoverBody() + { + return _rentedBodyArray; + } + + public void ReturnHeaderBuffer() + { + ArrayPool.Shared.Return(_rentedHeaderArray); + } + + public void ReturnMethodBuffer() + { + ArrayPool.Shared.Return(_rentedMethodBytes); + } } } diff --git a/projects/RabbitMQ.Client/client/impl/MainSession.cs b/projects/RabbitMQ.Client/client/impl/MainSession.cs index 49c2f0ef30..d600a67eec 100644 --- a/projects/RabbitMQ.Client/client/impl/MainSession.cs +++ b/projects/RabbitMQ.Client/client/impl/MainSession.cs @@ -37,79 +37,80 @@ using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Framing.Impl; -namespace RabbitMQ.Client.Impl; - -///Small ISession implementation used only for channel 0. -internal sealed class MainSession : Session +namespace RabbitMQ.Client.Impl { - private volatile bool _closeServerInitiated; - private volatile bool _closing; - private readonly object _lock = new object(); - - public MainSession(Connection connection) : base(connection, 0) + ///Small ISession implementation used only for channel 0. + internal sealed class MainSession : Session { - } + private volatile bool _closeServerInitiated; + private volatile bool _closing; + private readonly object _lock = new object(); - public override bool HandleFrame(in InboundFrame frame) - { - if (_closing) + public MainSession(Connection connection) : base(connection, 0) { - // We are closing - if (!_closeServerInitiated && frame.Type == FrameType.FrameMethod) + } + + public override bool HandleFrame(in InboundFrame frame) + { + if (_closing) { - // This isn't a server initiated close and we have a method frame - switch (Connection.Protocol.DecodeCommandIdFrom(frame.Payload.Span)) + // We are closing + if (!_closeServerInitiated && frame.Type == FrameType.FrameMethod) { - case ProtocolCommandId.ConnectionClose: - return base.HandleFrame(in frame); - case ProtocolCommandId.ConnectionCloseOk: - // This is the reply (CloseOk) we were looking for - // Call any listener attached to this session - Connection.NotifyReceivedCloseOk(); - break; + // This isn't a server initiated close and we have a method frame + switch (Connection.Protocol.DecodeCommandIdFrom(frame.Payload.Span)) + { + case ProtocolCommandId.ConnectionClose: + return base.HandleFrame(in frame); + case ProtocolCommandId.ConnectionCloseOk: + // This is the reply (CloseOk) we were looking for + // Call any listener attached to this session + Connection.NotifyReceivedCloseOk(); + break; + } } + + // Either a non-method frame, or not what we were looking + // for. Ignore it - we're quiescing. + return true; } - // Either a non-method frame, or not what we were looking - // for. Ignore it - we're quiescing. - return true; + return base.HandleFrame(in frame); } - return base.HandleFrame(in frame); - } - - /// Set channel 0 as quiescing - /// - /// Method should be idempotent. Cannot use base.Close - /// method call because that would prevent us from - /// sending/receiving Close/CloseOk commands - /// - public void SetSessionClosing(bool closeServerInitiated) - { - if (!_closing) + /// Set channel 0 as quiescing + /// + /// Method should be idempotent. Cannot use base.Close + /// method call because that would prevent us from + /// sending/receiving Close/CloseOk commands + /// + public void SetSessionClosing(bool closeServerInitiated) { - lock (_lock) + if (!_closing) { - if (!_closing) + lock (_lock) { - _closing = true; - _closeServerInitiated = closeServerInitiated; + if (!_closing) + { + _closing = true; + _closeServerInitiated = closeServerInitiated; + } } } } - } - public override void Transmit(ref T cmd) - { - if (_closing && // Are we closing? - cmd.ProtocolCommandId != ProtocolCommandId.ConnectionCloseOk && // is this not a close-ok? - (_closeServerInitiated || cmd.ProtocolCommandId != ProtocolCommandId.ConnectionClose)) // is this either server initiated or not a close? + public override void Transmit(ref T cmd) { - // We shouldn't do anything since we are closing, not sending a connection-close-ok command - // and this is either a server-initiated close or not a connection-close command. - return; - } + if (_closing && // Are we closing? + cmd.ProtocolCommandId != ProtocolCommandId.ConnectionCloseOk && // is this not a close-ok? + (_closeServerInitiated || cmd.ProtocolCommandId != ProtocolCommandId.ConnectionClose)) // is this either server initiated or not a close? + { + // We shouldn't do anything since we are closing, not sending a connection-close-ok command + // and this is either a server-initiated close or not a connection-close command. + return; + } - base.Transmit(ref cmd); + base.Transmit(ref cmd); + } } } diff --git a/projects/RabbitMQ.Client/client/impl/ModelBase.cs b/projects/RabbitMQ.Client/client/impl/ModelBase.cs index dcfb75af8a..6913218232 100644 --- a/projects/RabbitMQ.Client/client/impl/ModelBase.cs +++ b/projects/RabbitMQ.Client/client/impl/ModelBase.cs @@ -44,1153 +44,1154 @@ using RabbitMQ.Client.Framing.Impl; using RabbitMQ.Util; -namespace RabbitMQ.Client.Impl; - -internal abstract class ModelBase : IModel, IRecoverable +namespace RabbitMQ.Client.Impl { - ///Only used to kick-start a connection open - ///sequence. See - internal BlockingCell m_connectionStartCell; + internal abstract class ModelBase : IModel, IRecoverable + { + ///Only used to kick-start a connection open + ///sequence. See + internal BlockingCell m_connectionStartCell; - private readonly RpcContinuationQueue _continuationQueue = new RpcContinuationQueue(); - private readonly ManualResetEventSlim _flowControlBlock = new ManualResetEventSlim(true); + private readonly RpcContinuationQueue _continuationQueue = new RpcContinuationQueue(); + private readonly ManualResetEventSlim _flowControlBlock = new ManualResetEventSlim(true); - private readonly object _rpcLock = new object(); - private readonly object _confirmLock = new object(); - private readonly LinkedList _pendingDeliveryTags = new LinkedList(); + private readonly object _rpcLock = new object(); + private readonly object _confirmLock = new object(); + private readonly LinkedList _pendingDeliveryTags = new LinkedList(); - private bool _onlyAcksReceived = true; + private bool _onlyAcksReceived = true; - private ShutdownEventArgs _closeReason; - public ShutdownEventArgs CloseReason => Volatile.Read(ref _closeReason); + private ShutdownEventArgs _closeReason; + public ShutdownEventArgs CloseReason => Volatile.Read(ref _closeReason); - internal IConsumerDispatcher ConsumerDispatcher { get; } + internal IConsumerDispatcher ConsumerDispatcher { get; } - protected ModelBase(ConnectionConfig config, ISession session) - { - ContinuationTimeout = config.ContinuationTimeout; - ConsumerDispatcher = config.DispatchConsumersAsync ? - (IConsumerDispatcher)new AsyncConsumerDispatcher(this, config.DispatchConsumerConcurrency) : - new ConsumerDispatcher(this, config.DispatchConsumerConcurrency); - - Action onException = (exception, context) => OnCallbackException(CallbackExceptionEventArgs.Build(exception, context)); - _basicAcksWrapper = new EventingWrapper("OnBasicAck", onException); - _basicNacksWrapper = new EventingWrapper("OnBasicNack", onException); - _basicRecoverOkWrapper = new EventingWrapper("OnBasicRecover", onException); - _basicReturnWrapper = new EventingWrapper("OnBasicReturn", onException); - _callbackExceptionWrapper = new EventingWrapper(string.Empty, (exception, context) => { }); - _flowControlWrapper = new EventingWrapper("OnFlowControl", onException); - _modelShutdownWrapper = new EventingWrapper("OnModelShutdown", onException); - _recoveryWrapper = new EventingWrapper("OnModelRecovery", onException); - session.CommandReceived = HandleCommand; - session.SessionShutdown += OnSessionShutdown; - Session = session; - } + protected ModelBase(ConnectionConfig config, ISession session) + { + ContinuationTimeout = config.ContinuationTimeout; + ConsumerDispatcher = config.DispatchConsumersAsync ? + (IConsumerDispatcher)new AsyncConsumerDispatcher(this, config.DispatchConsumerConcurrency) : + new ConsumerDispatcher(this, config.DispatchConsumerConcurrency); + + Action onException = (exception, context) => OnCallbackException(CallbackExceptionEventArgs.Build(exception, context)); + _basicAcksWrapper = new EventingWrapper("OnBasicAck", onException); + _basicNacksWrapper = new EventingWrapper("OnBasicNack", onException); + _basicRecoverOkWrapper = new EventingWrapper("OnBasicRecover", onException); + _basicReturnWrapper = new EventingWrapper("OnBasicReturn", onException); + _callbackExceptionWrapper = new EventingWrapper(string.Empty, (exception, context) => { }); + _flowControlWrapper = new EventingWrapper("OnFlowControl", onException); + _modelShutdownWrapper = new EventingWrapper("OnModelShutdown", onException); + _recoveryWrapper = new EventingWrapper("OnModelRecovery", onException); + session.CommandReceived = HandleCommand; + session.SessionShutdown += OnSessionShutdown; + Session = session; + } - internal TimeSpan HandshakeContinuationTimeout { get; set; } = TimeSpan.FromSeconds(10); - public TimeSpan ContinuationTimeout { get; set; } + internal TimeSpan HandshakeContinuationTimeout { get; set; } = TimeSpan.FromSeconds(10); + public TimeSpan ContinuationTimeout { get; set; } - public event EventHandler BasicAcks - { - add => _basicAcksWrapper.AddHandler(value); - remove => _basicAcksWrapper.RemoveHandler(value); - } - private EventingWrapper _basicAcksWrapper; + public event EventHandler BasicAcks + { + add => _basicAcksWrapper.AddHandler(value); + remove => _basicAcksWrapper.RemoveHandler(value); + } + private EventingWrapper _basicAcksWrapper; - public event EventHandler BasicNacks - { - add => _basicNacksWrapper.AddHandler(value); - remove => _basicNacksWrapper.RemoveHandler(value); - } - private EventingWrapper _basicNacksWrapper; + public event EventHandler BasicNacks + { + add => _basicNacksWrapper.AddHandler(value); + remove => _basicNacksWrapper.RemoveHandler(value); + } + private EventingWrapper _basicNacksWrapper; - public event EventHandler BasicRecoverOk - { - add => _basicRecoverOkWrapper.AddHandler(value); - remove => _basicRecoverOkWrapper.RemoveHandler(value); - } - private EventingWrapper _basicRecoverOkWrapper; + public event EventHandler BasicRecoverOk + { + add => _basicRecoverOkWrapper.AddHandler(value); + remove => _basicRecoverOkWrapper.RemoveHandler(value); + } + private EventingWrapper _basicRecoverOkWrapper; - public event EventHandler BasicReturn - { - add => _basicReturnWrapper.AddHandler(value); - remove => _basicReturnWrapper.RemoveHandler(value); - } - private EventingWrapper _basicReturnWrapper; + public event EventHandler BasicReturn + { + add => _basicReturnWrapper.AddHandler(value); + remove => _basicReturnWrapper.RemoveHandler(value); + } + private EventingWrapper _basicReturnWrapper; - public event EventHandler CallbackException - { - add => _callbackExceptionWrapper.AddHandler(value); - remove => _callbackExceptionWrapper.RemoveHandler(value); - } - private EventingWrapper _callbackExceptionWrapper; + public event EventHandler CallbackException + { + add => _callbackExceptionWrapper.AddHandler(value); + remove => _callbackExceptionWrapper.RemoveHandler(value); + } + private EventingWrapper _callbackExceptionWrapper; - public event EventHandler FlowControl - { - add => _flowControlWrapper.AddHandler(value); - remove => _flowControlWrapper.RemoveHandler(value); - } - private EventingWrapper _flowControlWrapper; + public event EventHandler FlowControl + { + add => _flowControlWrapper.AddHandler(value); + remove => _flowControlWrapper.RemoveHandler(value); + } + private EventingWrapper _flowControlWrapper; - public event EventHandler ModelShutdown - { - add + public event EventHandler ModelShutdown { - if (IsOpen) + add { - _modelShutdownWrapper.AddHandler(value); - } - else - { - value(this, CloseReason); + if (IsOpen) + { + _modelShutdownWrapper.AddHandler(value); + } + else + { + value(this, CloseReason); + } } + remove => _modelShutdownWrapper.RemoveHandler(value); } - remove => _modelShutdownWrapper.RemoveHandler(value); - } - private EventingWrapper _modelShutdownWrapper; - - public event EventHandler Recovery - { - add => _recoveryWrapper.AddHandler(value); - remove => _recoveryWrapper.RemoveHandler(value); - } - private EventingWrapper _recoveryWrapper; + private EventingWrapper _modelShutdownWrapper; - internal void RunRecoveryEventHandlers(object sender) - { - _recoveryWrapper.Invoke(sender, EventArgs.Empty); - } + public event EventHandler Recovery + { + add => _recoveryWrapper.AddHandler(value); + remove => _recoveryWrapper.RemoveHandler(value); + } + private EventingWrapper _recoveryWrapper; - public int ChannelNumber => ((Session)Session).ChannelNumber; + internal void RunRecoveryEventHandlers(object sender) + { + _recoveryWrapper.Invoke(sender, EventArgs.Empty); + } - public IBasicConsumer DefaultConsumer - { - get => ConsumerDispatcher.DefaultConsumer; - set => ConsumerDispatcher.DefaultConsumer = value; - } + public int ChannelNumber => ((Session)Session).ChannelNumber; - public bool IsClosed => !IsOpen; + public IBasicConsumer DefaultConsumer + { + get => ConsumerDispatcher.DefaultConsumer; + set => ConsumerDispatcher.DefaultConsumer = value; + } - public bool IsOpen => CloseReason is null; + public bool IsClosed => !IsOpen; - public ulong NextPublishSeqNo { get; private set; } + public bool IsOpen => CloseReason is null; - public ISession Session { get; private set; } + public ulong NextPublishSeqNo { get; private set; } - protected void TakeOver(ModelBase other) - { - _basicAcksWrapper.Takeover(other._basicAcksWrapper); - _basicNacksWrapper.Takeover(other._basicNacksWrapper); - _basicRecoverOkWrapper.Takeover(other._basicRecoverOkWrapper); - _basicReturnWrapper.Takeover(other._basicReturnWrapper); - _callbackExceptionWrapper.Takeover(other._callbackExceptionWrapper); - _flowControlWrapper.Takeover(other._flowControlWrapper); - _modelShutdownWrapper.Takeover(other._modelShutdownWrapper); - _recoveryWrapper.Takeover(other._recoveryWrapper); - } + public ISession Session { get; private set; } - public void Close(ushort replyCode, string replyText, bool abort) - { - _ = CloseAsync(new ShutdownEventArgs(ShutdownInitiator.Application, replyCode, replyText), abort); - } + protected void TakeOver(ModelBase other) + { + _basicAcksWrapper.Takeover(other._basicAcksWrapper); + _basicNacksWrapper.Takeover(other._basicNacksWrapper); + _basicRecoverOkWrapper.Takeover(other._basicRecoverOkWrapper); + _basicReturnWrapper.Takeover(other._basicReturnWrapper); + _callbackExceptionWrapper.Takeover(other._callbackExceptionWrapper); + _flowControlWrapper.Takeover(other._flowControlWrapper); + _modelShutdownWrapper.Takeover(other._modelShutdownWrapper); + _recoveryWrapper.Takeover(other._recoveryWrapper); + } - private async Task CloseAsync(ShutdownEventArgs reason, bool abort) - { - var k = new ShutdownContinuation(); - ModelShutdown += k.OnConnectionShutdown; + public void Close(ushort replyCode, string replyText, bool abort) + { + _ = CloseAsync(new ShutdownEventArgs(ShutdownInitiator.Application, replyCode, replyText), abort); + } - try + private async Task CloseAsync(ShutdownEventArgs reason, bool abort) { - ConsumerDispatcher.Quiesce(); - if (SetCloseReason(reason)) + var k = new ShutdownContinuation(); + ModelShutdown += k.OnConnectionShutdown; + + try { - _Private_ChannelClose(reason.ReplyCode, reason.ReplyText, 0, 0); - } + ConsumerDispatcher.Quiesce(); + if (SetCloseReason(reason)) + { + _Private_ChannelClose(reason.ReplyCode, reason.ReplyText, 0, 0); + } - k.Wait(TimeSpan.FromMilliseconds(10000)); - await ConsumerDispatcher.WaitForShutdownAsync().ConfigureAwait(false); - } - catch (AlreadyClosedException) - { - if (!abort) + k.Wait(TimeSpan.FromMilliseconds(10000)); + await ConsumerDispatcher.WaitForShutdownAsync().ConfigureAwait(false); + } + catch (AlreadyClosedException) { - throw; + if (!abort) + { + throw; + } } - } - catch (IOException) - { - if (!abort) + catch (IOException) { - throw; + if (!abort) + { + throw; + } } - } - catch (Exception) - { - if (!abort) + catch (Exception) { - throw; + if (!abort) + { + throw; + } + } + finally + { + ModelShutdown -= k.OnConnectionShutdown; } } - finally - { - ModelShutdown -= k.OnConnectionShutdown; - } - } - internal void ConnectionOpen(string virtualHost) - { - var k = new SimpleBlockingRpcContinuation(); - lock (_rpcLock) + internal void ConnectionOpen(string virtualHost) { - Enqueue(k); - try - { - _Private_ConnectionOpen(virtualHost); - } - catch (AlreadyClosedException) + var k = new SimpleBlockingRpcContinuation(); + lock (_rpcLock) { - // let continuation throw OperationInterruptedException, - // which is a much more suitable exception before connection - // negotiation finishes + Enqueue(k); + try + { + _Private_ConnectionOpen(virtualHost); + } + catch (AlreadyClosedException) + { + // let continuation throw OperationInterruptedException, + // which is a much more suitable exception before connection + // negotiation finishes + } + k.GetReply(HandshakeContinuationTimeout); } - k.GetReply(HandshakeContinuationTimeout); } - } - internal ConnectionSecureOrTune ConnectionSecureOk(byte[] response) - { - var k = new ConnectionStartRpcContinuation(); - lock (_rpcLock) + internal ConnectionSecureOrTune ConnectionSecureOk(byte[] response) { - Enqueue(k); - try + var k = new ConnectionStartRpcContinuation(); + lock (_rpcLock) { - _Private_ConnectionSecureOk(response); + Enqueue(k); + try + { + _Private_ConnectionSecureOk(response); + } + catch (AlreadyClosedException) + { + // let continuation throw OperationInterruptedException, + // which is a much more suitable exception before connection + // negotiation finishes + } + k.GetReply(HandshakeContinuationTimeout); } - catch (AlreadyClosedException) + return k.m_result; + } + + internal ConnectionSecureOrTune ConnectionStartOk(IDictionary clientProperties, string mechanism, byte[] response, string locale) + { + var k = new ConnectionStartRpcContinuation(); + lock (_rpcLock) { - // let continuation throw OperationInterruptedException, - // which is a much more suitable exception before connection - // negotiation finishes + Enqueue(k); + try + { + _Private_ConnectionStartOk(clientProperties, mechanism, + response, locale); + } + catch (AlreadyClosedException) + { + // let continuation throw OperationInterruptedException, + // which is a much more suitable exception before connection + // negotiation finishes + } + k.GetReply(HandshakeContinuationTimeout); } - k.GetReply(HandshakeContinuationTimeout); + return k.m_result; } - return k.m_result; - } - internal ConnectionSecureOrTune ConnectionStartOk(IDictionary clientProperties, string mechanism, byte[] response, string locale) - { - var k = new ConnectionStartRpcContinuation(); - lock (_rpcLock) + protected abstract bool DispatchAsynchronous(in IncomingCommand cmd); + + protected void Enqueue(IRpcContinuation k) { - Enqueue(k); - try + if (IsOpen) { - _Private_ConnectionStartOk(clientProperties, mechanism, - response, locale); + _continuationQueue.Enqueue(k); } - catch (AlreadyClosedException) + else { - // let continuation throw OperationInterruptedException, - // which is a much more suitable exception before connection - // negotiation finishes + k.HandleModelShutdown(CloseReason); } - k.GetReply(HandshakeContinuationTimeout); } - return k.m_result; - } - protected abstract bool DispatchAsynchronous(in IncomingCommand cmd); - - protected void Enqueue(IRpcContinuation k) - { - if (IsOpen) + internal void FinishClose() { - _continuationQueue.Enqueue(k); + var reason = CloseReason; + if (reason != null) + { + Session.Close(reason); + } + + m_connectionStartCell?.ContinueWithValue(null); } - else + + private void HandleCommand(in IncomingCommand cmd) { - k.HandleModelShutdown(CloseReason); + if (!DispatchAsynchronous(in cmd)) // Was asynchronous. Already processed. No need to process further. + { + _continuationQueue.Next().HandleCommand(in cmd); + } } - } - internal void FinishClose() - { - var reason = CloseReason; - if (reason != null) + protected void ModelRpc(ref TMethod method, ProtocolCommandId returnCommandId) + where TMethod : struct, IOutgoingAmqpMethod { - Session.Close(reason); - } + var k = new SimpleBlockingRpcContinuation(); + IncomingCommand reply; + lock (_rpcLock) + { + Enqueue(k); + Session.Transmit(ref method); + k.GetReply(ContinuationTimeout, out reply); + } - m_connectionStartCell?.ContinueWithValue(null); - } + reply.ReturnMethodBuffer(); - private void HandleCommand(in IncomingCommand cmd) - { - if (!DispatchAsynchronous(in cmd)) // Was asynchronous. Already processed. No need to process further. - { - _continuationQueue.Next().HandleCommand(in cmd); + if (reply.CommandId != returnCommandId) + { + throw new UnexpectedMethodException(reply.CommandId, returnCommandId); + } } - } - protected void ModelRpc(ref TMethod method, ProtocolCommandId returnCommandId) - where TMethod : struct, IOutgoingAmqpMethod - { - var k = new SimpleBlockingRpcContinuation(); - IncomingCommand reply; - lock (_rpcLock) + protected TReturn ModelRpc(ref TMethod method, ProtocolCommandId returnCommandId, Func, TReturn> createFunc) + where TMethod : struct, IOutgoingAmqpMethod { - Enqueue(k); - Session.Transmit(ref method); - k.GetReply(ContinuationTimeout, out reply); - } + var k = new SimpleBlockingRpcContinuation(); + IncomingCommand reply; - reply.ReturnMethodBuffer(); + lock (_rpcLock) + { + Enqueue(k); + Session.Transmit(ref method); + k.GetReply(ContinuationTimeout, out reply); + } - if (reply.CommandId != returnCommandId) - { - throw new UnexpectedMethodException(reply.CommandId, returnCommandId); - } - } + if (reply.CommandId != returnCommandId) + { + reply.ReturnMethodBuffer(); + throw new UnexpectedMethodException(reply.CommandId, returnCommandId); + } - protected TReturn ModelRpc(ref TMethod method, ProtocolCommandId returnCommandId, Func, TReturn> createFunc) - where TMethod : struct, IOutgoingAmqpMethod - { - var k = new SimpleBlockingRpcContinuation(); - IncomingCommand reply; + var returnValue = createFunc(reply.MethodBytes); + reply.ReturnMethodBuffer(); + return returnValue; + } - lock (_rpcLock) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected void ModelSend(ref T method) where T : struct, IOutgoingAmqpMethod { - Enqueue(k); Session.Transmit(ref method); - k.GetReply(ContinuationTimeout, out reply); } - if (reply.CommandId != returnCommandId) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected void ModelSend(ref TMethod method, ref THeader header, ReadOnlyMemory body) + where TMethod : struct, IOutgoingAmqpMethod + where THeader : IAmqpHeader { - reply.ReturnMethodBuffer(); - throw new UnexpectedMethodException(reply.CommandId, returnCommandId); + if (!_flowControlBlock.IsSet) + { + _flowControlBlock.Wait(); + } + Session.Transmit(ref method, ref header, body); } - var returnValue = createFunc(reply.MethodBytes); - reply.ReturnMethodBuffer(); - return returnValue; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - protected void ModelSend(ref T method) where T : struct, IOutgoingAmqpMethod - { - Session.Transmit(ref method); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - protected void ModelSend(ref TMethod method, ref THeader header, ReadOnlyMemory body) - where TMethod : struct, IOutgoingAmqpMethod - where THeader : IAmqpHeader - { - if (!_flowControlBlock.IsSet) + internal void OnCallbackException(CallbackExceptionEventArgs args) { - _flowControlBlock.Wait(); + _callbackExceptionWrapper.Invoke(this, args); } - Session.Transmit(ref method, ref header, body); - } - internal void OnCallbackException(CallbackExceptionEventArgs args) - { - _callbackExceptionWrapper.Invoke(this, args); - } - - ///Broadcasts notification of the final shutdown of the model. - /// - /// - ///Do not call anywhere other than at the end of OnSessionShutdown. - /// - /// - ///Must not be called when m_closeReason is null, because - ///otherwise there's a window when a new continuation could be - ///being enqueued at the same time as we're broadcasting the - ///shutdown event. See the definition of Enqueue() above. - /// - /// - private void OnModelShutdown(ShutdownEventArgs reason) - { - _continuationQueue.HandleModelShutdown(reason); - _modelShutdownWrapper.Invoke(this, reason); - lock (_confirmLock) + ///Broadcasts notification of the final shutdown of the model. + /// + /// + ///Do not call anywhere other than at the end of OnSessionShutdown. + /// + /// + ///Must not be called when m_closeReason is null, because + ///otherwise there's a window when a new continuation could be + ///being enqueued at the same time as we're broadcasting the + ///shutdown event. See the definition of Enqueue() above. + /// + /// + private void OnModelShutdown(ShutdownEventArgs reason) { - if (_confirmsTaskCompletionSources?.Count > 0) + _continuationQueue.HandleModelShutdown(reason); + _modelShutdownWrapper.Invoke(this, reason); + lock (_confirmLock) { - var exception = new AlreadyClosedException(reason); - foreach (var confirmsTaskCompletionSource in _confirmsTaskCompletionSources) + if (_confirmsTaskCompletionSources?.Count > 0) { - confirmsTaskCompletionSource.TrySetException(exception); + var exception = new AlreadyClosedException(reason); + foreach (var confirmsTaskCompletionSource in _confirmsTaskCompletionSources) + { + confirmsTaskCompletionSource.TrySetException(exception); + } + _confirmsTaskCompletionSources.Clear(); } - _confirmsTaskCompletionSources.Clear(); } + _flowControlBlock.Set(); } - _flowControlBlock.Set(); - } - private void OnSessionShutdown(object sender, ShutdownEventArgs reason) - { - ConsumerDispatcher.Quiesce(); - SetCloseReason(reason); - OnModelShutdown(reason); - ConsumerDispatcher.ShutdownAsync(reason).GetAwaiter().GetResult(); - } - - internal bool SetCloseReason(ShutdownEventArgs reason) - { - return System.Threading.Interlocked.CompareExchange(ref _closeReason, reason, null) is null; - } - - public override string ToString() - => Session.ToString(); - - void IDisposable.Dispose() - { - Dispose(true); - } + private void OnSessionShutdown(object sender, ShutdownEventArgs reason) + { + ConsumerDispatcher.Quiesce(); + SetCloseReason(reason); + OnModelShutdown(reason); + ConsumerDispatcher.ShutdownAsync(reason).GetAwaiter().GetResult(); + } - protected virtual void Dispose(bool disposing) - { - if (disposing) + internal bool SetCloseReason(ShutdownEventArgs reason) { - // dispose managed resources - this.Abort(); + return System.Threading.Interlocked.CompareExchange(ref _closeReason, reason, null) is null; } - // dispose unmanaged resources - } + public override string ToString() + => Session.ToString(); - public abstract void ConnectionTuneOk(ushort channelMax, uint frameMax, ushort heartbeat); + void IDisposable.Dispose() + { + Dispose(true); + } - protected void HandleBasicAck(in IncomingCommand cmd) - { - var ack = new BasicAck(cmd.MethodBytes.Span); - cmd.ReturnMethodBuffer(); - if (!_basicAcksWrapper.IsEmpty) + protected virtual void Dispose(bool disposing) { - var args = new BasicAckEventArgs + if (disposing) { - DeliveryTag = ack._deliveryTag, - Multiple = ack._multiple - }; - _basicAcksWrapper.Invoke(this, args); + // dispose managed resources + this.Abort(); + } + + // dispose unmanaged resources } - HandleAckNack(ack._deliveryTag, ack._multiple, false); - } + public abstract void ConnectionTuneOk(ushort channelMax, uint frameMax, ushort heartbeat); - protected void HandleBasicNack(in IncomingCommand cmd) - { - var nack = new BasicNack(cmd.MethodBytes.Span); - cmd.ReturnMethodBuffer(); - if (!_basicNacksWrapper.IsEmpty) + protected void HandleBasicAck(in IncomingCommand cmd) { - var args = new BasicNackEventArgs + var ack = new BasicAck(cmd.MethodBytes.Span); + cmd.ReturnMethodBuffer(); + if (!_basicAcksWrapper.IsEmpty) { - DeliveryTag = nack._deliveryTag, - Multiple = nack._multiple, - Requeue = nack._requeue - }; - _basicNacksWrapper.Invoke(this, args); + var args = new BasicAckEventArgs + { + DeliveryTag = ack._deliveryTag, + Multiple = ack._multiple + }; + _basicAcksWrapper.Invoke(this, args); + } + + HandleAckNack(ack._deliveryTag, ack._multiple, false); } - HandleAckNack(nack._deliveryTag, nack._multiple, true); - } + protected void HandleBasicNack(in IncomingCommand cmd) + { + var nack = new BasicNack(cmd.MethodBytes.Span); + cmd.ReturnMethodBuffer(); + if (!_basicNacksWrapper.IsEmpty) + { + var args = new BasicNackEventArgs + { + DeliveryTag = nack._deliveryTag, + Multiple = nack._multiple, + Requeue = nack._requeue + }; + _basicNacksWrapper.Invoke(this, args); + } - protected void HandleAckNack(ulong deliveryTag, bool multiple, bool isNack) - { - // No need to do this if publisher confirms have never been enabled. - if (NextPublishSeqNo > 0) + HandleAckNack(nack._deliveryTag, nack._multiple, true); + } + + protected void HandleAckNack(ulong deliveryTag, bool multiple, bool isNack) { - // let's take a lock so we can assume that deliveryTags are unique, never duplicated and always sorted - lock (_confirmLock) + // No need to do this if publisher confirms have never been enabled. + if (NextPublishSeqNo > 0) { - // No need to do anything if there are no delivery tags in the list - if (_pendingDeliveryTags.Count > 0) + // let's take a lock so we can assume that deliveryTags are unique, never duplicated and always sorted + lock (_confirmLock) { - if (multiple) + // No need to do anything if there are no delivery tags in the list + if (_pendingDeliveryTags.Count > 0) { - while (_pendingDeliveryTags.First.Value < deliveryTag) + if (multiple) { - _pendingDeliveryTags.RemoveFirst(); + while (_pendingDeliveryTags.First.Value < deliveryTag) + { + _pendingDeliveryTags.RemoveFirst(); + } + + if (_pendingDeliveryTags.First.Value == deliveryTag) + { + _pendingDeliveryTags.RemoveFirst(); + } } - - if (_pendingDeliveryTags.First.Value == deliveryTag) + else { - _pendingDeliveryTags.RemoveFirst(); + _pendingDeliveryTags.Remove(deliveryTag); } } - else - { - _pendingDeliveryTags.Remove(deliveryTag); - } - } - _onlyAcksReceived = _onlyAcksReceived && !isNack; + _onlyAcksReceived = _onlyAcksReceived && !isNack; - if (_pendingDeliveryTags.Count == 0 && _confirmsTaskCompletionSources.Count > 0) - { - // Done, mark tasks - foreach (var confirmsTaskCompletionSource in _confirmsTaskCompletionSources) + if (_pendingDeliveryTags.Count == 0 && _confirmsTaskCompletionSources.Count > 0) { - confirmsTaskCompletionSource.TrySetResult(_onlyAcksReceived); + // Done, mark tasks + foreach (var confirmsTaskCompletionSource in _confirmsTaskCompletionSources) + { + confirmsTaskCompletionSource.TrySetResult(_onlyAcksReceived); + } + _confirmsTaskCompletionSources.Clear(); + _onlyAcksReceived = true; } - _confirmsTaskCompletionSources.Clear(); - _onlyAcksReceived = true; } } } - } - protected void HandleBasicCancel(in IncomingCommand cmd) - { - var consumerTag = new Client.Framing.Impl.BasicCancel(cmd.MethodBytes.Span)._consumerTag; - cmd.ReturnMethodBuffer(); - ConsumerDispatcher.HandleBasicCancel(consumerTag); - } + protected void HandleBasicCancel(in IncomingCommand cmd) + { + var consumerTag = new Client.Framing.Impl.BasicCancel(cmd.MethodBytes.Span)._consumerTag; + cmd.ReturnMethodBuffer(); + ConsumerDispatcher.HandleBasicCancel(consumerTag); + } - protected void HandleBasicCancelOk(in IncomingCommand cmd) - { - var k = (BasicConsumerRpcContinuation)_continuationQueue.Next(); - var consumerTag = new Client.Framing.Impl.BasicCancelOk(cmd.MethodBytes.Span)._consumerTag; - cmd.ReturnMethodBuffer(); - ConsumerDispatcher.HandleBasicCancelOk(consumerTag); - k.HandleCommand(IncomingCommand.Empty); // release the continuation. - } + protected void HandleBasicCancelOk(in IncomingCommand cmd) + { + var k = (BasicConsumerRpcContinuation)_continuationQueue.Next(); + var consumerTag = new Client.Framing.Impl.BasicCancelOk(cmd.MethodBytes.Span)._consumerTag; + cmd.ReturnMethodBuffer(); + ConsumerDispatcher.HandleBasicCancelOk(consumerTag); + k.HandleCommand(IncomingCommand.Empty); // release the continuation. + } - protected void HandleBasicConsumeOk(in IncomingCommand cmd) - { - var consumerTag = new Client.Framing.Impl.BasicConsumeOk(cmd.MethodBytes.Span)._consumerTag; - cmd.ReturnMethodBuffer(); - var k = (BasicConsumerRpcContinuation)_continuationQueue.Next(); - k.m_consumerTag = consumerTag; - ConsumerDispatcher.HandleBasicConsumeOk(k.m_consumer, consumerTag); - k.HandleCommand(IncomingCommand.Empty); // release the continuation. - } + protected void HandleBasicConsumeOk(in IncomingCommand cmd) + { + var consumerTag = new Client.Framing.Impl.BasicConsumeOk(cmd.MethodBytes.Span)._consumerTag; + cmd.ReturnMethodBuffer(); + var k = (BasicConsumerRpcContinuation)_continuationQueue.Next(); + k.m_consumerTag = consumerTag; + ConsumerDispatcher.HandleBasicConsumeOk(k.m_consumer, consumerTag); + k.HandleCommand(IncomingCommand.Empty); // release the continuation. + } - protected void HandleBasicDeliver(in IncomingCommand cmd) - { - var method = new Client.Framing.Impl.BasicDeliver(cmd.MethodBytes.Span); - cmd.ReturnMethodBuffer(); - var header = new ReadOnlyBasicProperties(cmd.HeaderBytes.Span); - cmd.ReturnHeaderBuffer(); + protected void HandleBasicDeliver(in IncomingCommand cmd) + { + var method = new Client.Framing.Impl.BasicDeliver(cmd.MethodBytes.Span); + cmd.ReturnMethodBuffer(); + var header = new ReadOnlyBasicProperties(cmd.HeaderBytes.Span); + cmd.ReturnHeaderBuffer(); + + ConsumerDispatcher.HandleBasicDeliver( + method._consumerTag, + AdjustDeliveryTag(method._deliveryTag), + method._redelivered, + method._exchange, + method._routingKey, + header, + cmd.Body, + cmd.TakeoverBody()); + } + + protected void HandleBasicGetOk(in IncomingCommand cmd) + { + var method = new BasicGetOk(cmd.MethodBytes.Span); + cmd.ReturnMethodBuffer(); + var header = new ReadOnlyBasicProperties(cmd.HeaderBytes.Span); + cmd.ReturnHeaderBuffer(); - ConsumerDispatcher.HandleBasicDeliver( - method._consumerTag, + var k = (BasicGetRpcContinuation)_continuationQueue.Next(); + k.m_result = new BasicGetResult( AdjustDeliveryTag(method._deliveryTag), method._redelivered, method._exchange, method._routingKey, + method._messageCount, header, cmd.Body, cmd.TakeoverBody()); - } - - protected void HandleBasicGetOk(in IncomingCommand cmd) - { - var method = new BasicGetOk(cmd.MethodBytes.Span); - cmd.ReturnMethodBuffer(); - var header = new ReadOnlyBasicProperties(cmd.HeaderBytes.Span); - cmd.ReturnHeaderBuffer(); - - var k = (BasicGetRpcContinuation)_continuationQueue.Next(); - k.m_result = new BasicGetResult( - AdjustDeliveryTag(method._deliveryTag), - method._redelivered, - method._exchange, - method._routingKey, - method._messageCount, - header, - cmd.Body, - cmd.TakeoverBody()); - k.HandleCommand(IncomingCommand.Empty); // release the continuation. - } - - protected virtual ulong AdjustDeliveryTag(ulong deliveryTag) - { - return deliveryTag; - } - - protected void HandleBasicGetEmpty() - { - var k = (BasicGetRpcContinuation)_continuationQueue.Next(); - k.m_result = null; - k.HandleCommand(IncomingCommand.Empty); // release the continuation. - } - - protected void HandleBasicRecoverOk() - { - var k = (SimpleBlockingRpcContinuation)_continuationQueue.Next(); - _basicRecoverOkWrapper.Invoke(this, EventArgs.Empty); - k.HandleCommand(IncomingCommand.Empty); - } - - protected void HandleBasicReturn(in IncomingCommand cmd) - { - if (!_basicReturnWrapper.IsEmpty) - { - var basicReturn = new BasicReturn(cmd.MethodBytes.Span); - var e = new BasicReturnEventArgs - { - ReplyCode = basicReturn._replyCode, - ReplyText = basicReturn._replyText, - Exchange = basicReturn._exchange, - RoutingKey = basicReturn._routingKey, - BasicProperties = new ReadOnlyBasicProperties(cmd.HeaderBytes.Span), - Body = cmd.Body - }; - _basicReturnWrapper.Invoke(this, e); - } - cmd.ReturnMethodBuffer(); - cmd.ReturnHeaderBuffer(); - ArrayPool.Shared.Return(cmd.TakeoverBody()); - } - - protected void HandleChannelClose(in IncomingCommand cmd) - { - var channelClose = new ChannelClose(cmd.MethodBytes.Span); - cmd.ReturnMethodBuffer(); - SetCloseReason(new ShutdownEventArgs(ShutdownInitiator.Peer, - channelClose._replyCode, - channelClose._replyText, - channelClose._classId, - channelClose._methodId)); - - Session.Close(CloseReason, false); - try - { - _Private_ChannelCloseOk(); - } - finally - { - Session.Notify(); + k.HandleCommand(IncomingCommand.Empty); // release the continuation. } - } - - protected void HandleChannelCloseOk() - { - FinishClose(); - } - protected void HandleChannelFlow(in IncomingCommand cmd) - { - var active = new ChannelFlow(cmd.MethodBytes.Span)._active; - cmd.ReturnMethodBuffer(); - if (active) + protected virtual ulong AdjustDeliveryTag(ulong deliveryTag) { - _flowControlBlock.Set(); + return deliveryTag; } - else + + protected void HandleBasicGetEmpty() { - _flowControlBlock.Reset(); + var k = (BasicGetRpcContinuation)_continuationQueue.Next(); + k.m_result = null; + k.HandleCommand(IncomingCommand.Empty); // release the continuation. } - _Private_ChannelFlowOk(active); - - if (!_flowControlWrapper.IsEmpty) + protected void HandleBasicRecoverOk() { - _flowControlWrapper.Invoke(this, new FlowControlEventArgs(active)); + var k = (SimpleBlockingRpcContinuation)_continuationQueue.Next(); + _basicRecoverOkWrapper.Invoke(this, EventArgs.Empty); + k.HandleCommand(IncomingCommand.Empty); } - } - protected void HandleConnectionBlocked(in IncomingCommand cmd) - { - var reason = new ConnectionBlocked(cmd.MethodBytes.Span)._reason; - cmd.ReturnMethodBuffer(); - Session.Connection.HandleConnectionBlocked(reason); - } + protected void HandleBasicReturn(in IncomingCommand cmd) + { + if (!_basicReturnWrapper.IsEmpty) + { + var basicReturn = new BasicReturn(cmd.MethodBytes.Span); + var e = new BasicReturnEventArgs + { + ReplyCode = basicReturn._replyCode, + ReplyText = basicReturn._replyText, + Exchange = basicReturn._exchange, + RoutingKey = basicReturn._routingKey, + BasicProperties = new ReadOnlyBasicProperties(cmd.HeaderBytes.Span), + Body = cmd.Body + }; + _basicReturnWrapper.Invoke(this, e); + } + cmd.ReturnMethodBuffer(); + cmd.ReturnHeaderBuffer(); + ArrayPool.Shared.Return(cmd.TakeoverBody()); + } - protected void HandleConnectionClose(in IncomingCommand cmd) - { - var method = new ConnectionClose(cmd.MethodBytes.Span); - cmd.ReturnMethodBuffer(); - var reason = new ShutdownEventArgs(ShutdownInitiator.Peer, method._replyCode, method._replyText, method._classId, method._methodId); - try + protected void HandleChannelClose(in IncomingCommand cmd) { - Session.Connection.InternalClose(reason); - _Private_ConnectionCloseOk(); - SetCloseReason(Session.Connection.CloseReason); + var channelClose = new ChannelClose(cmd.MethodBytes.Span); + cmd.ReturnMethodBuffer(); + SetCloseReason(new ShutdownEventArgs(ShutdownInitiator.Peer, + channelClose._replyCode, + channelClose._replyText, + channelClose._classId, + channelClose._methodId)); + + Session.Close(CloseReason, false); + try + { + _Private_ChannelCloseOk(); + } + finally + { + Session.Notify(); + } } - catch (IOException) + + protected void HandleChannelCloseOk() { - // Ignored. We're only trying to be polite by sending - // the close-ok, after all. + FinishClose(); } - catch (AlreadyClosedException) + + protected void HandleChannelFlow(in IncomingCommand cmd) { - // Ignored. We're only trying to be polite by sending - // the close-ok, after all. + var active = new ChannelFlow(cmd.MethodBytes.Span)._active; + cmd.ReturnMethodBuffer(); + if (active) + { + _flowControlBlock.Set(); + } + else + { + _flowControlBlock.Reset(); + } + + _Private_ChannelFlowOk(active); + + if (!_flowControlWrapper.IsEmpty) + { + _flowControlWrapper.Invoke(this, new FlowControlEventArgs(active)); + } } - } - protected void HandleConnectionSecure(in IncomingCommand cmd) - { - var challenge = new ConnectionSecure(cmd.MethodBytes.Span)._challenge; - cmd.ReturnMethodBuffer(); - var k = (ConnectionStartRpcContinuation)_continuationQueue.Next(); - k.m_result = new ConnectionSecureOrTune - { - m_challenge = challenge - }; - k.HandleCommand(IncomingCommand.Empty); // release the continuation. - } + protected void HandleConnectionBlocked(in IncomingCommand cmd) + { + var reason = new ConnectionBlocked(cmd.MethodBytes.Span)._reason; + cmd.ReturnMethodBuffer(); + Session.Connection.HandleConnectionBlocked(reason); + } - protected void HandleConnectionStart(in IncomingCommand cmd) - { - if (m_connectionStartCell is null) + protected void HandleConnectionClose(in IncomingCommand cmd) { - var reason = new ShutdownEventArgs(ShutdownInitiator.Library, Constants.CommandInvalid, "Unexpected Connection.Start"); - Session.Connection.Close(reason, false, InternalConstants.DefaultConnectionCloseTimeout); + var method = new ConnectionClose(cmd.MethodBytes.Span); + cmd.ReturnMethodBuffer(); + var reason = new ShutdownEventArgs(ShutdownInitiator.Peer, method._replyCode, method._replyText, method._classId, method._methodId); + try + { + Session.Connection.InternalClose(reason); + _Private_ConnectionCloseOk(); + SetCloseReason(Session.Connection.CloseReason); + } + catch (IOException) + { + // Ignored. We're only trying to be polite by sending + // the close-ok, after all. + } + catch (AlreadyClosedException) + { + // Ignored. We're only trying to be polite by sending + // the close-ok, after all. + } } - var method = new ConnectionStart(cmd.MethodBytes.Span); - cmd.ReturnMethodBuffer(); - var details = new ConnectionStartDetails + protected void HandleConnectionSecure(in IncomingCommand cmd) { - m_versionMajor = method._versionMajor, - m_versionMinor = method._versionMinor, - m_serverProperties = method._serverProperties, - m_mechanisms = method._mechanisms, - m_locales = method._locales - }; - m_connectionStartCell.ContinueWithValue(details); - m_connectionStartCell = null; - } + var challenge = new ConnectionSecure(cmd.MethodBytes.Span)._challenge; + cmd.ReturnMethodBuffer(); + var k = (ConnectionStartRpcContinuation)_continuationQueue.Next(); + k.m_result = new ConnectionSecureOrTune + { + m_challenge = challenge + }; + k.HandleCommand(IncomingCommand.Empty); // release the continuation. + } - protected void HandleConnectionTune(in IncomingCommand cmd) - { - var connectionTune = new ConnectionTune(cmd.MethodBytes.Span); - cmd.ReturnMethodBuffer(); - var k = (ConnectionStartRpcContinuation)_continuationQueue.Next(); - k.m_result = new ConnectionSecureOrTune + protected void HandleConnectionStart(in IncomingCommand cmd) { - m_tuneDetails = + if (m_connectionStartCell is null) { - m_channelMax = connectionTune._channelMax, - m_frameMax = connectionTune._frameMax, - m_heartbeatInSeconds = connectionTune._heartbeat + var reason = new ShutdownEventArgs(ShutdownInitiator.Library, Constants.CommandInvalid, "Unexpected Connection.Start"); + Session.Connection.Close(reason, false, InternalConstants.DefaultConnectionCloseTimeout); } - }; - k.HandleCommand(IncomingCommand.Empty); // release the continuation. - } - - protected void HandleConnectionUnblocked() - { - Session.Connection.HandleConnectionUnblocked(); - } - protected void HandleQueueDeclareOk(in IncomingCommand cmd) - { - var method = new Client.Framing.Impl.QueueDeclareOk(cmd.MethodBytes.Span); - cmd.ReturnMethodBuffer(); - var k = (QueueDeclareRpcContinuation)_continuationQueue.Next(); - k.m_result = new QueueDeclareOk(method._queue, method._messageCount, method._consumerCount); - k.HandleCommand(IncomingCommand.Empty); // release the continuation. - } + var method = new ConnectionStart(cmd.MethodBytes.Span); + cmd.ReturnMethodBuffer(); + var details = new ConnectionStartDetails + { + m_versionMajor = method._versionMajor, + m_versionMinor = method._versionMinor, + m_serverProperties = method._serverProperties, + m_mechanisms = method._mechanisms, + m_locales = method._locales + }; + m_connectionStartCell.ContinueWithValue(details); + m_connectionStartCell = null; + } - public abstract void _Private_BasicCancel(string consumerTag, bool nowait); + protected void HandleConnectionTune(in IncomingCommand cmd) + { + var connectionTune = new ConnectionTune(cmd.MethodBytes.Span); + cmd.ReturnMethodBuffer(); + var k = (ConnectionStartRpcContinuation)_continuationQueue.Next(); + k.m_result = new ConnectionSecureOrTune + { + m_tuneDetails = + { + m_channelMax = connectionTune._channelMax, + m_frameMax = connectionTune._frameMax, + m_heartbeatInSeconds = connectionTune._heartbeat + } + }; + k.HandleCommand(IncomingCommand.Empty); // release the continuation. + } - public abstract void _Private_BasicConsume(string queue, string consumerTag, bool noLocal, bool autoAck, bool exclusive, bool nowait, IDictionary arguments); + protected void HandleConnectionUnblocked() + { + Session.Connection.HandleConnectionUnblocked(); + } - public abstract void _Private_BasicGet(string queue, bool autoAck); + protected void HandleQueueDeclareOk(in IncomingCommand cmd) + { + var method = new Client.Framing.Impl.QueueDeclareOk(cmd.MethodBytes.Span); + cmd.ReturnMethodBuffer(); + var k = (QueueDeclareRpcContinuation)_continuationQueue.Next(); + k.m_result = new QueueDeclareOk(method._queue, method._messageCount, method._consumerCount); + k.HandleCommand(IncomingCommand.Empty); // release the continuation. + } - public abstract void _Private_BasicRecover(bool requeue); + public abstract void _Private_BasicCancel(string consumerTag, bool nowait); - public abstract void _Private_ChannelClose(ushort replyCode, string replyText, ushort classId, ushort methodId); + public abstract void _Private_BasicConsume(string queue, string consumerTag, bool noLocal, bool autoAck, bool exclusive, bool nowait, IDictionary arguments); - public abstract void _Private_ChannelCloseOk(); + public abstract void _Private_BasicGet(string queue, bool autoAck); - public abstract void _Private_ChannelFlowOk(bool active); + public abstract void _Private_BasicRecover(bool requeue); - public abstract void _Private_ChannelOpen(); + public abstract void _Private_ChannelClose(ushort replyCode, string replyText, ushort classId, ushort methodId); - public abstract void _Private_ConfirmSelect(bool nowait); + public abstract void _Private_ChannelCloseOk(); - public abstract void _Private_ConnectionCloseOk(); + public abstract void _Private_ChannelFlowOk(bool active); - public abstract void _Private_ConnectionOpen(string virtualHost); + public abstract void _Private_ChannelOpen(); - public abstract void _Private_ConnectionSecureOk(byte[] response); + public abstract void _Private_ConfirmSelect(bool nowait); - public abstract void _Private_ConnectionStartOk(IDictionary clientProperties, string mechanism, byte[] response, string locale); + public abstract void _Private_ConnectionCloseOk(); - public abstract void _Private_UpdateSecret(byte[] @newSecret, string @reason); + public abstract void _Private_ConnectionOpen(string virtualHost); - public abstract void _Private_ExchangeBind(string destination, string source, string routingKey, bool nowait, IDictionary arguments); + public abstract void _Private_ConnectionSecureOk(byte[] response); - public abstract void _Private_ExchangeDeclare(string exchange, string type, bool passive, bool durable, bool autoDelete, bool @internal, bool nowait, IDictionary arguments); + public abstract void _Private_ConnectionStartOk(IDictionary clientProperties, string mechanism, byte[] response, string locale); - public abstract void _Private_ExchangeDelete(string exchange, bool ifUnused, bool nowait); + public abstract void _Private_UpdateSecret(byte[] @newSecret, string @reason); - public abstract void _Private_ExchangeUnbind(string destination, string source, string routingKey, bool nowait, IDictionary arguments); + public abstract void _Private_ExchangeBind(string destination, string source, string routingKey, bool nowait, IDictionary arguments); - public abstract void _Private_QueueBind(string queue, string exchange, string routingKey, bool nowait, IDictionary arguments); + public abstract void _Private_ExchangeDeclare(string exchange, string type, bool passive, bool durable, bool autoDelete, bool @internal, bool nowait, IDictionary arguments); - public abstract void _Private_QueueDeclare(string queue, bool passive, bool durable, bool exclusive, bool autoDelete, bool nowait, IDictionary arguments); + public abstract void _Private_ExchangeDelete(string exchange, bool ifUnused, bool nowait); - public abstract uint _Private_QueueDelete(string queue, bool ifUnused, bool ifEmpty, bool nowait); + public abstract void _Private_ExchangeUnbind(string destination, string source, string routingKey, bool nowait, IDictionary arguments); - public abstract uint _Private_QueuePurge(string queue, bool nowait); + public abstract void _Private_QueueBind(string queue, string exchange, string routingKey, bool nowait, IDictionary arguments); - public abstract void BasicAck(ulong deliveryTag, bool multiple); + public abstract void _Private_QueueDeclare(string queue, bool passive, bool durable, bool exclusive, bool autoDelete, bool nowait, IDictionary arguments); - public void BasicCancel(string consumerTag) - { - var k = new BasicConsumerRpcContinuation { m_consumerTag = consumerTag }; + public abstract uint _Private_QueueDelete(string queue, bool ifUnused, bool ifEmpty, bool nowait); - lock (_rpcLock) - { - Enqueue(k); - _Private_BasicCancel(consumerTag, false); - k.GetReply(ContinuationTimeout); - } - } + public abstract uint _Private_QueuePurge(string queue, bool nowait); - public void BasicCancelNoWait(string consumerTag) - { - _Private_BasicCancel(consumerTag, true); - ConsumerDispatcher.GetAndRemoveConsumer(consumerTag); - } + public abstract void BasicAck(ulong deliveryTag, bool multiple); - public string BasicConsume(string queue, bool autoAck, string consumerTag, bool noLocal, bool exclusive, IDictionary arguments, IBasicConsumer consumer) - { - // TODO: Replace with flag - if (ConsumerDispatcher is AsyncConsumerDispatcher) + public void BasicCancel(string consumerTag) { - if (!(consumer is IAsyncBasicConsumer)) + var k = new BasicConsumerRpcContinuation { m_consumerTag = consumerTag }; + + lock (_rpcLock) { - // TODO: Friendly message - throw new InvalidOperationException("In the async mode you have to use an async consumer"); + Enqueue(k); + _Private_BasicCancel(consumerTag, false); + k.GetReply(ContinuationTimeout); } } - var k = new BasicConsumerRpcContinuation { m_consumer = consumer }; - - lock (_rpcLock) + public void BasicCancelNoWait(string consumerTag) { - Enqueue(k); - // Non-nowait. We have an unconventional means of getting - // the RPC response, but a response is still expected. - _Private_BasicConsume(queue, consumerTag, noLocal, autoAck, exclusive, - /*nowait:*/ false, arguments); - k.GetReply(ContinuationTimeout); + _Private_BasicCancel(consumerTag, true); + ConsumerDispatcher.GetAndRemoveConsumer(consumerTag); } - string actualConsumerTag = k.m_consumerTag; - return actualConsumerTag; - } - - public BasicGetResult BasicGet(string queue, bool autoAck) - { - var k = new BasicGetRpcContinuation(); - lock (_rpcLock) + public string BasicConsume(string queue, bool autoAck, string consumerTag, bool noLocal, bool exclusive, IDictionary arguments, IBasicConsumer consumer) { - Enqueue(k); - _Private_BasicGet(queue, autoAck); - k.GetReply(ContinuationTimeout); - } + // TODO: Replace with flag + if (ConsumerDispatcher is AsyncConsumerDispatcher) + { + if (!(consumer is IAsyncBasicConsumer)) + { + // TODO: Friendly message + throw new InvalidOperationException("In the async mode you have to use an async consumer"); + } + } - return k.m_result; - } + var k = new BasicConsumerRpcContinuation { m_consumer = consumer }; - public abstract void BasicNack(ulong deliveryTag, bool multiple, bool requeue); + lock (_rpcLock) + { + Enqueue(k); + // Non-nowait. We have an unconventional means of getting + // the RPC response, but a response is still expected. + _Private_BasicConsume(queue, consumerTag, noLocal, autoAck, exclusive, + /*nowait:*/ false, arguments); + k.GetReply(ContinuationTimeout); + } + string actualConsumerTag = k.m_consumerTag; - public void BasicPublish(string exchange, string routingKey, ref TProperties basicProperties, ReadOnlyMemory body, bool mandatory) - where TProperties : IReadOnlyBasicProperties, IAmqpHeader - { - if (NextPublishSeqNo > 0) + return actualConsumerTag; + } + + public BasicGetResult BasicGet(string queue, bool autoAck) { - lock (_confirmLock) + var k = new BasicGetRpcContinuation(); + lock (_rpcLock) { - _pendingDeliveryTags.AddLast(NextPublishSeqNo++); + Enqueue(k); + _Private_BasicGet(queue, autoAck); + k.GetReply(ContinuationTimeout); } + + return k.m_result; } - var cmd = new BasicPublish(exchange, routingKey, mandatory, default); - ModelSend(ref cmd, ref basicProperties, body); - } + public abstract void BasicNack(ulong deliveryTag, bool multiple, bool requeue); - public void BasicPublish(CachedString exchange, CachedString routingKey, ref TProperties basicProperties, ReadOnlyMemory body, bool mandatory) - where TProperties : IReadOnlyBasicProperties, IAmqpHeader - { - if (NextPublishSeqNo > 0) + public void BasicPublish(string exchange, string routingKey, ref TProperties basicProperties, ReadOnlyMemory body, bool mandatory) + where TProperties : IReadOnlyBasicProperties, IAmqpHeader { - lock (_confirmLock) + if (NextPublishSeqNo > 0) { - _pendingDeliveryTags.AddLast(NextPublishSeqNo++); + lock (_confirmLock) + { + _pendingDeliveryTags.AddLast(NextPublishSeqNo++); + } } - } - var cmd = new BasicPublishMemory(exchange.Bytes, routingKey.Bytes, mandatory, default); - ModelSend(ref cmd, ref basicProperties, body); - } + var cmd = new BasicPublish(exchange, routingKey, mandatory, default); + ModelSend(ref cmd, ref basicProperties, body); + } - public void UpdateSecret(string newSecret, string reason) - { - if (newSecret is null) + public void BasicPublish(CachedString exchange, CachedString routingKey, ref TProperties basicProperties, ReadOnlyMemory body, bool mandatory) + where TProperties : IReadOnlyBasicProperties, IAmqpHeader { - throw new ArgumentNullException(nameof(newSecret)); + if (NextPublishSeqNo > 0) + { + lock (_confirmLock) + { + _pendingDeliveryTags.AddLast(NextPublishSeqNo++); + } + } + + var cmd = new BasicPublishMemory(exchange.Bytes, routingKey.Bytes, mandatory, default); + ModelSend(ref cmd, ref basicProperties, body); } - if (reason is null) + public void UpdateSecret(string newSecret, string reason) { - throw new ArgumentNullException(nameof(reason)); - } + if (newSecret is null) + { + throw new ArgumentNullException(nameof(newSecret)); + } - _Private_UpdateSecret(Encoding.UTF8.GetBytes(newSecret), reason); - } + if (reason is null) + { + throw new ArgumentNullException(nameof(reason)); + } - public abstract void BasicQos(uint prefetchSize, ushort prefetchCount, bool global); + _Private_UpdateSecret(Encoding.UTF8.GetBytes(newSecret), reason); + } - public void BasicRecover(bool requeue) - { - var k = new SimpleBlockingRpcContinuation(); + public abstract void BasicQos(uint prefetchSize, ushort prefetchCount, bool global); - lock (_rpcLock) + public void BasicRecover(bool requeue) { - Enqueue(k); - _Private_BasicRecover(requeue); - k.GetReply(ContinuationTimeout); + var k = new SimpleBlockingRpcContinuation(); + + lock (_rpcLock) + { + Enqueue(k); + _Private_BasicRecover(requeue); + k.GetReply(ContinuationTimeout); + } } - } - public abstract void BasicRecoverAsync(bool requeue); + public abstract void BasicRecoverAsync(bool requeue); - public abstract void BasicReject(ulong deliveryTag, bool requeue); + public abstract void BasicReject(ulong deliveryTag, bool requeue); - public void ConfirmSelect() - { - if (NextPublishSeqNo == 0UL) + public void ConfirmSelect() { - _confirmsTaskCompletionSources = new List>(); - NextPublishSeqNo = 1; - } + if (NextPublishSeqNo == 0UL) + { + _confirmsTaskCompletionSources = new List>(); + NextPublishSeqNo = 1; + } - _Private_ConfirmSelect(false); - } + _Private_ConfirmSelect(false); + } - public void ExchangeBind(string destination, string source, string routingKey, IDictionary arguments) - { - _Private_ExchangeBind(destination, source, routingKey, false, arguments); - } + public void ExchangeBind(string destination, string source, string routingKey, IDictionary arguments) + { + _Private_ExchangeBind(destination, source, routingKey, false, arguments); + } - public void ExchangeBindNoWait(string destination, string source, string routingKey, IDictionary arguments) - { - _Private_ExchangeBind(destination, source, routingKey, true, arguments); - } + public void ExchangeBindNoWait(string destination, string source, string routingKey, IDictionary arguments) + { + _Private_ExchangeBind(destination, source, routingKey, true, arguments); + } - public void ExchangeDeclare(string exchange, string type, bool durable, bool autoDelete, IDictionary arguments) - { - _Private_ExchangeDeclare(exchange, type, false, durable, autoDelete, false, false, arguments); - } + public void ExchangeDeclare(string exchange, string type, bool durable, bool autoDelete, IDictionary arguments) + { + _Private_ExchangeDeclare(exchange, type, false, durable, autoDelete, false, false, arguments); + } - public void ExchangeDeclareNoWait(string exchange, string type, bool durable, bool autoDelete, IDictionary arguments) - { - _Private_ExchangeDeclare(exchange, type, false, durable, autoDelete, false, true, arguments); - } + public void ExchangeDeclareNoWait(string exchange, string type, bool durable, bool autoDelete, IDictionary arguments) + { + _Private_ExchangeDeclare(exchange, type, false, durable, autoDelete, false, true, arguments); + } - public void ExchangeDeclarePassive(string exchange) - { - _Private_ExchangeDeclare(exchange, "", true, false, false, false, false, null); - } + public void ExchangeDeclarePassive(string exchange) + { + _Private_ExchangeDeclare(exchange, "", true, false, false, false, false, null); + } - public void ExchangeDelete(string exchange, bool ifUnused) - { - _Private_ExchangeDelete(exchange, ifUnused, false); - } + public void ExchangeDelete(string exchange, bool ifUnused) + { + _Private_ExchangeDelete(exchange, ifUnused, false); + } - public void ExchangeDeleteNoWait(string exchange, bool ifUnused) - { - _Private_ExchangeDelete(exchange, ifUnused, true); - } + public void ExchangeDeleteNoWait(string exchange, bool ifUnused) + { + _Private_ExchangeDelete(exchange, ifUnused, true); + } - public void ExchangeUnbind(string destination, string source, string routingKey, IDictionary arguments) - { - _Private_ExchangeUnbind(destination, source, routingKey, false, arguments); - } + public void ExchangeUnbind(string destination, string source, string routingKey, IDictionary arguments) + { + _Private_ExchangeUnbind(destination, source, routingKey, false, arguments); + } - public void ExchangeUnbindNoWait(string destination, string source, string routingKey, IDictionary arguments) - { - _Private_ExchangeUnbind(destination, source, routingKey, true, arguments); - } + public void ExchangeUnbindNoWait(string destination, string source, string routingKey, IDictionary arguments) + { + _Private_ExchangeUnbind(destination, source, routingKey, true, arguments); + } - public void QueueBind(string queue, string exchange, string routingKey, IDictionary arguments) - { - _Private_QueueBind(queue, exchange, routingKey, false, arguments); - } + public void QueueBind(string queue, string exchange, string routingKey, IDictionary arguments) + { + _Private_QueueBind(queue, exchange, routingKey, false, arguments); + } - public void QueueBindNoWait(string queue, string exchange, string routingKey, IDictionary arguments) - { - _Private_QueueBind(queue, exchange, routingKey, true, arguments); - } + public void QueueBindNoWait(string queue, string exchange, string routingKey, IDictionary arguments) + { + _Private_QueueBind(queue, exchange, routingKey, true, arguments); + } - public QueueDeclareOk QueueDeclare(string queue, bool durable, bool exclusive, bool autoDelete, IDictionary arguments) - { - return QueueDeclare(queue, false, durable, exclusive, autoDelete, arguments); - } + public QueueDeclareOk QueueDeclare(string queue, bool durable, bool exclusive, bool autoDelete, IDictionary arguments) + { + return QueueDeclare(queue, false, durable, exclusive, autoDelete, arguments); + } - public void QueueDeclareNoWait(string queue, bool durable, bool exclusive, bool autoDelete, IDictionary arguments) - { - _Private_QueueDeclare(queue, false, durable, exclusive, autoDelete, true, arguments); - } + public void QueueDeclareNoWait(string queue, bool durable, bool exclusive, bool autoDelete, IDictionary arguments) + { + _Private_QueueDeclare(queue, false, durable, exclusive, autoDelete, true, arguments); + } - public QueueDeclareOk QueueDeclarePassive(string queue) - { - return QueueDeclare(queue, true, false, false, false, null); - } + public QueueDeclareOk QueueDeclarePassive(string queue) + { + return QueueDeclare(queue, true, false, false, false, null); + } - public uint MessageCount(string queue) - { - QueueDeclareOk ok = QueueDeclarePassive(queue); - return ok.MessageCount; - } + public uint MessageCount(string queue) + { + QueueDeclareOk ok = QueueDeclarePassive(queue); + return ok.MessageCount; + } - public uint ConsumerCount(string queue) - { - QueueDeclareOk ok = QueueDeclarePassive(queue); - return ok.ConsumerCount; - } + public uint ConsumerCount(string queue) + { + QueueDeclareOk ok = QueueDeclarePassive(queue); + return ok.ConsumerCount; + } - public uint QueueDelete(string queue, bool ifUnused, bool ifEmpty) - { - return _Private_QueueDelete(queue, ifUnused, ifEmpty, false); - } + public uint QueueDelete(string queue, bool ifUnused, bool ifEmpty) + { + return _Private_QueueDelete(queue, ifUnused, ifEmpty, false); + } - public void QueueDeleteNoWait(string queue, bool ifUnused, bool ifEmpty) - { - _Private_QueueDelete(queue, ifUnused, ifEmpty, true); - } + public void QueueDeleteNoWait(string queue, bool ifUnused, bool ifEmpty) + { + _Private_QueueDelete(queue, ifUnused, ifEmpty, true); + } - public uint QueuePurge(string queue) - { - return _Private_QueuePurge(queue, false); - } + public uint QueuePurge(string queue) + { + return _Private_QueuePurge(queue, false); + } - public abstract void QueueUnbind(string queue, string exchange, string routingKey, IDictionary arguments); + public abstract void QueueUnbind(string queue, string exchange, string routingKey, IDictionary arguments); - public abstract void TxCommit(); + public abstract void TxCommit(); - public abstract void TxRollback(); + public abstract void TxRollback(); - public abstract void TxSelect(); + public abstract void TxSelect(); - private List> _confirmsTaskCompletionSources; + private List> _confirmsTaskCompletionSources; - public Task WaitForConfirmsAsync(CancellationToken token = default) - { - if (NextPublishSeqNo == 0UL) + public Task WaitForConfirmsAsync(CancellationToken token = default) { - throw new InvalidOperationException("Confirms not selected"); - } + if (NextPublishSeqNo == 0UL) + { + throw new InvalidOperationException("Confirms not selected"); + } - TaskCompletionSource tcs; - lock (_confirmLock) - { - if (_pendingDeliveryTags.Count == 0) + TaskCompletionSource tcs; + lock (_confirmLock) { - if (_onlyAcksReceived == false) + if (_pendingDeliveryTags.Count == 0) { - _onlyAcksReceived = true; - return Task.FromResult(false); + if (_onlyAcksReceived == false) + { + _onlyAcksReceived = true; + return Task.FromResult(false); + } + return Task.FromResult(true); } - return Task.FromResult(true); + + tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + _confirmsTaskCompletionSources.Add(tcs); } - tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); - _confirmsTaskCompletionSources.Add(tcs); - } + if (!token.CanBeCanceled) + { + return tcs.Task; + } - if (!token.CanBeCanceled) - { - return tcs.Task; + return WaitForConfirmsWithTokenAsync(tcs, token); } - return WaitForConfirmsWithTokenAsync(tcs, token); - } - - private async Task WaitForConfirmsWithTokenAsync(TaskCompletionSource tcs, CancellationToken token) - { - CancellationTokenRegistration tokenRegistration = + private async Task WaitForConfirmsWithTokenAsync(TaskCompletionSource tcs, CancellationToken token) + { + CancellationTokenRegistration tokenRegistration = #if NETSTANDARD - token.Register( + token.Register( #else - token.UnsafeRegister( + token.UnsafeRegister( #endif - state => ((TaskCompletionSource)state).TrySetCanceled(), tcs); + state => ((TaskCompletionSource)state).TrySetCanceled(), tcs); - try - { - return await tcs.Task.ConfigureAwait(false); - } - finally - { + try + { + return await tcs.Task.ConfigureAwait(false); + } + finally + { #if NETSTANDARD - tokenRegistration.Dispose(); + tokenRegistration.Dispose(); #else - await tokenRegistration.DisposeAsync().ConfigureAwait(false); + await tokenRegistration.DisposeAsync().ConfigureAwait(false); #endif + } } - } - public async Task WaitForConfirmsOrDieAsync(CancellationToken token = default) - { - try + public async Task WaitForConfirmsOrDieAsync(CancellationToken token = default) { - bool onlyAcksReceived = await WaitForConfirmsAsync(token).ConfigureAwait(false); - if (onlyAcksReceived) + try { - return; - } + bool onlyAcksReceived = await WaitForConfirmsAsync(token).ConfigureAwait(false); + if (onlyAcksReceived) + { + return; + } - await CloseAsync( - new ShutdownEventArgs(ShutdownInitiator.Library, Constants.ReplySuccess, "Nacks Received", - new IOException("nack received")), - false).ConfigureAwait(false); - } - catch (TaskCanceledException exception) - { - await CloseAsync(new ShutdownEventArgs(ShutdownInitiator.Library, - Constants.ReplySuccess, - "Timed out waiting for acks", - exception), - false).ConfigureAwait(false); + await CloseAsync( + new ShutdownEventArgs(ShutdownInitiator.Library, Constants.ReplySuccess, "Nacks Received", + new IOException("nack received")), + false).ConfigureAwait(false); + } + catch (TaskCanceledException exception) + { + await CloseAsync(new ShutdownEventArgs(ShutdownInitiator.Library, + Constants.ReplySuccess, + "Timed out waiting for acks", + exception), + false).ConfigureAwait(false); + } } - } - private QueueDeclareOk QueueDeclare(string queue, bool passive, bool durable, bool exclusive, bool autoDelete, IDictionary arguments) - { - var k = new QueueDeclareRpcContinuation(); - lock (_rpcLock) + private QueueDeclareOk QueueDeclare(string queue, bool passive, bool durable, bool exclusive, bool autoDelete, IDictionary arguments) { - Enqueue(k); - _Private_QueueDeclare(queue, passive, durable, exclusive, autoDelete, false, arguments); - k.GetReply(ContinuationTimeout); + var k = new QueueDeclareRpcContinuation(); + lock (_rpcLock) + { + Enqueue(k); + _Private_QueueDeclare(queue, passive, durable, exclusive, autoDelete, false, arguments); + k.GetReply(ContinuationTimeout); + } + return k.m_result; } - return k.m_result; - } - public class BasicConsumerRpcContinuation : SimpleBlockingRpcContinuation - { - public IBasicConsumer m_consumer; - public string m_consumerTag; - } + public class BasicConsumerRpcContinuation : SimpleBlockingRpcContinuation + { + public IBasicConsumer m_consumer; + public string m_consumerTag; + } - public class BasicGetRpcContinuation : SimpleBlockingRpcContinuation - { - public BasicGetResult m_result; - } + public class BasicGetRpcContinuation : SimpleBlockingRpcContinuation + { + public BasicGetResult m_result; + } - public class ConnectionStartRpcContinuation : SimpleBlockingRpcContinuation - { - public ConnectionSecureOrTune m_result; - } + public class ConnectionStartRpcContinuation : SimpleBlockingRpcContinuation + { + public ConnectionSecureOrTune m_result; + } - public class QueueDeclareRpcContinuation : SimpleBlockingRpcContinuation - { - public QueueDeclareOk m_result; + public class QueueDeclareRpcContinuation : SimpleBlockingRpcContinuation + { + public QueueDeclareOk m_result; + } } } diff --git a/projects/RabbitMQ.Client/client/impl/ProtocolBase.cs b/projects/RabbitMQ.Client/client/impl/ProtocolBase.cs index b150feb376..a8d6e16c2e 100644 --- a/projects/RabbitMQ.Client/client/impl/ProtocolBase.cs +++ b/projects/RabbitMQ.Client/client/impl/ProtocolBase.cs @@ -34,51 +34,52 @@ using RabbitMQ.Client.client.framing; using RabbitMQ.Client.Impl; -namespace RabbitMQ.Client.Framing.Impl; - -internal abstract class ProtocolBase : IProtocol +namespace RabbitMQ.Client.Framing.Impl { - public Dictionary Capabilities; - - protected ProtocolBase() + internal abstract class ProtocolBase : IProtocol { - Capabilities = new Dictionary(6) + public Dictionary Capabilities; + + protected ProtocolBase() { - ["publisher_confirms"] = WireFormatting.TrueBoolean, - ["exchange_exchange_bindings"] = WireFormatting.TrueBoolean, - ["basic.nack"] = WireFormatting.TrueBoolean, - ["consumer_cancel_notify"] = WireFormatting.TrueBoolean, - ["connection.blocked"] = WireFormatting.TrueBoolean, - ["authentication_failure_close"] = WireFormatting.TrueBoolean - }; - } + Capabilities = new Dictionary(6) + { + ["publisher_confirms"] = WireFormatting.TrueBoolean, + ["exchange_exchange_bindings"] = WireFormatting.TrueBoolean, + ["basic.nack"] = WireFormatting.TrueBoolean, + ["consumer_cancel_notify"] = WireFormatting.TrueBoolean, + ["connection.blocked"] = WireFormatting.TrueBoolean, + ["authentication_failure_close"] = WireFormatting.TrueBoolean + }; + } - public abstract string ApiName { get; } - public abstract int DefaultPort { get; } + public abstract string ApiName { get; } + public abstract int DefaultPort { get; } - public abstract int MajorVersion { get; } - public abstract int MinorVersion { get; } - public abstract int Revision { get; } + public abstract int MajorVersion { get; } + public abstract int MinorVersion { get; } + public abstract int Revision { get; } - public AmqpVersion Version - { - get { return new AmqpVersion(MajorVersion, MinorVersion); } - } + public AmqpVersion Version + { + get { return new AmqpVersion(MajorVersion, MinorVersion); } + } - internal abstract ProtocolCommandId DecodeCommandIdFrom(ReadOnlySpan span); + internal abstract ProtocolCommandId DecodeCommandIdFrom(ReadOnlySpan span); - public override bool Equals(object obj) - { - return GetType() == obj.GetType(); - } + public override bool Equals(object obj) + { + return GetType() == obj.GetType(); + } - public override int GetHashCode() - { - return GetType().GetHashCode(); - } + public override int GetHashCode() + { + return GetType().GetHashCode(); + } - public override string ToString() - { - return Version.ToString(); + public override string ToString() + { + return Version.ToString(); + } } } diff --git a/projects/RabbitMQ.Client/client/impl/RecordedBinding.cs b/projects/RabbitMQ.Client/client/impl/RecordedBinding.cs index 78b4171b6c..e9889d9a0c 100644 --- a/projects/RabbitMQ.Client/client/impl/RecordedBinding.cs +++ b/projects/RabbitMQ.Client/client/impl/RecordedBinding.cs @@ -32,80 +32,81 @@ using System; using System.Collections.Generic; -namespace RabbitMQ.Client.Impl; - -#nullable enable -internal readonly struct RecordedBinding : IEquatable +namespace RabbitMQ.Client.Impl { - private readonly bool _isQueueBinding; - private readonly string _destination; - private readonly string _source; - private readonly string _routingKey; - private readonly IDictionary? _arguments; - - public string Destination => _destination; - public string Source => _source; - - public RecordedBinding(bool isQueueBinding, string destination, string source, string routingKey, IDictionary? arguments) +#nullable enable + internal readonly struct RecordedBinding : IEquatable { - _isQueueBinding = isQueueBinding; - _destination = destination; - _source = source; - _routingKey = routingKey; - _arguments = arguments; - } + private readonly bool _isQueueBinding; + private readonly string _destination; + private readonly string _source; + private readonly string _routingKey; + private readonly IDictionary? _arguments; - public RecordedBinding(string destination, in RecordedBinding old) - { - _isQueueBinding = old._isQueueBinding; - _destination = destination; - _source = old._source; - _routingKey = old._routingKey; - _arguments = old._arguments; - } + public string Destination => _destination; + public string Source => _source; - public void Recover(IModel channel) - { - if (_isQueueBinding) + public RecordedBinding(bool isQueueBinding, string destination, string source, string routingKey, IDictionary? arguments) { - channel.QueueBind(_destination, _source, _routingKey, _arguments); + _isQueueBinding = isQueueBinding; + _destination = destination; + _source = source; + _routingKey = routingKey; + _arguments = arguments; } - else + + public RecordedBinding(string destination, in RecordedBinding old) { - channel.ExchangeBind(_destination, _source, _routingKey, _arguments); + _isQueueBinding = old._isQueueBinding; + _destination = destination; + _source = old._source; + _routingKey = old._routingKey; + _arguments = old._arguments; } - } - public bool Equals(RecordedBinding other) - { - return _isQueueBinding == other._isQueueBinding && _destination == other._destination && _source == other._source && - _routingKey == other._routingKey && _arguments == other._arguments; - } + public void Recover(IModel channel) + { + if (_isQueueBinding) + { + channel.QueueBind(_destination, _source, _routingKey, _arguments); + } + else + { + channel.ExchangeBind(_destination, _source, _routingKey, _arguments); + } + } - public override bool Equals(object? obj) - { - return obj is RecordedBinding other && Equals(other); - } + public bool Equals(RecordedBinding other) + { + return _isQueueBinding == other._isQueueBinding && _destination == other._destination && _source == other._source && + _routingKey == other._routingKey && _arguments == other._arguments; + } - public override int GetHashCode() - { -#if NETSTANDARD - unchecked + public override bool Equals(object? obj) { - int hashCode = _isQueueBinding.GetHashCode(); - hashCode = (hashCode * 397) ^ _destination.GetHashCode(); - hashCode = (hashCode * 397) ^ _source.GetHashCode(); - hashCode = (hashCode * 397) ^ _routingKey.GetHashCode(); - hashCode = (hashCode * 397) ^ (_arguments != null ? _arguments.GetHashCode() : 0); - return hashCode; + return obj is RecordedBinding other && Equals(other); } + + public override int GetHashCode() + { +#if NETSTANDARD + unchecked + { + int hashCode = _isQueueBinding.GetHashCode(); + hashCode = (hashCode * 397) ^ _destination.GetHashCode(); + hashCode = (hashCode * 397) ^ _source.GetHashCode(); + hashCode = (hashCode * 397) ^ _routingKey.GetHashCode(); + hashCode = (hashCode * 397) ^ (_arguments != null ? _arguments.GetHashCode() : 0); + return hashCode; + } #else - return HashCode.Combine(_isQueueBinding, _destination, _source, _routingKey, _arguments); + return HashCode.Combine(_isQueueBinding, _destination, _source, _routingKey, _arguments); #endif - } + } - public override string ToString() - { - return $"{nameof(RecordedBinding)}: isQueueBinding = '{_isQueueBinding}', source = '{_isQueueBinding}', destination = '{_destination}', routingKey = '{_routingKey}', arguments = '{_arguments}'"; + public override string ToString() + { + return $"{nameof(RecordedBinding)}: isQueueBinding = '{_isQueueBinding}', source = '{_isQueueBinding}', destination = '{_destination}', routingKey = '{_routingKey}', arguments = '{_arguments}'"; + } } } diff --git a/projects/RabbitMQ.Client/client/impl/RecordedConsumer.cs b/projects/RabbitMQ.Client/client/impl/RecordedConsumer.cs index 0ea480ec2e..8ed3a7b40e 100644 --- a/projects/RabbitMQ.Client/client/impl/RecordedConsumer.cs +++ b/projects/RabbitMQ.Client/client/impl/RecordedConsumer.cs @@ -31,42 +31,43 @@ using System.Collections.Generic; -namespace RabbitMQ.Client.Impl; - -#nullable enable -internal readonly struct RecordedConsumer +namespace RabbitMQ.Client.Impl { - public AutorecoveringModel Channel { get; } - public IBasicConsumer Consumer { get; } - public string Queue { get; } - public bool AutoAck { get; } - public string ConsumerTag { get; } - public bool Exclusive { get; } - public IDictionary? Arguments { get; } - - public RecordedConsumer(AutorecoveringModel channel, IBasicConsumer consumer, string queue, bool autoAck, string consumerTag, bool exclusive, IDictionary? arguments) +#nullable enable + internal readonly struct RecordedConsumer { - Channel = channel; - Consumer = consumer; - Queue = queue; - AutoAck = autoAck; - ConsumerTag = consumerTag; - Exclusive = exclusive; - Arguments = arguments; - } + public AutorecoveringModel Channel { get; } + public IBasicConsumer Consumer { get; } + public string Queue { get; } + public bool AutoAck { get; } + public string ConsumerTag { get; } + public bool Exclusive { get; } + public IDictionary? Arguments { get; } - public static RecordedConsumer WithNewConsumerTag(string newTag, in RecordedConsumer old) - { - return new RecordedConsumer(old.Channel, old.Consumer, old.Queue, old.AutoAck, newTag, old.Exclusive, old.Arguments); - } + public RecordedConsumer(AutorecoveringModel channel, IBasicConsumer consumer, string queue, bool autoAck, string consumerTag, bool exclusive, IDictionary? arguments) + { + Channel = channel; + Consumer = consumer; + Queue = queue; + AutoAck = autoAck; + ConsumerTag = consumerTag; + Exclusive = exclusive; + Arguments = arguments; + } - public static RecordedConsumer WithNewQueueNameTag(string newQueueName, in RecordedConsumer old) - { - return new RecordedConsumer(old.Channel, old.Consumer, newQueueName, old.AutoAck, old.ConsumerTag, old.Exclusive, old.Arguments); - } + public static RecordedConsumer WithNewConsumerTag(string newTag, in RecordedConsumer old) + { + return new RecordedConsumer(old.Channel, old.Consumer, old.Queue, old.AutoAck, newTag, old.Exclusive, old.Arguments); + } - public string Recover(IModel channel) - { - return channel.BasicConsume(Queue, AutoAck, ConsumerTag, false, Exclusive, Arguments, Consumer); + public static RecordedConsumer WithNewQueueNameTag(string newQueueName, in RecordedConsumer old) + { + return new RecordedConsumer(old.Channel, old.Consumer, newQueueName, old.AutoAck, old.ConsumerTag, old.Exclusive, old.Arguments); + } + + public string Recover(IModel channel) + { + return channel.BasicConsume(Queue, AutoAck, ConsumerTag, false, Exclusive, Arguments, Consumer); + } } } diff --git a/projects/RabbitMQ.Client/client/impl/RecordedExchange.cs b/projects/RabbitMQ.Client/client/impl/RecordedExchange.cs index 818ec72cc0..e3afd6b253 100644 --- a/projects/RabbitMQ.Client/client/impl/RecordedExchange.cs +++ b/projects/RabbitMQ.Client/client/impl/RecordedExchange.cs @@ -31,36 +31,37 @@ using System.Collections.Generic; -namespace RabbitMQ.Client.Impl; - -#nullable enable -internal readonly struct RecordedExchange +namespace RabbitMQ.Client.Impl { - private readonly string _name; - private readonly string _type; - private readonly bool _durable; - private readonly bool _isAutoDelete; - private readonly IDictionary? _arguments; +#nullable enable + internal readonly struct RecordedExchange + { + private readonly string _name; + private readonly string _type; + private readonly bool _durable; + private readonly bool _isAutoDelete; + private readonly IDictionary? _arguments; - public string Name => _name; - public bool IsAutoDelete => _isAutoDelete; + public string Name => _name; + public bool IsAutoDelete => _isAutoDelete; - public RecordedExchange(string name, string type, bool durable, bool isAutoDelete, IDictionary? arguments) - { - _name = name; - _type = type; - _durable = durable; - _isAutoDelete = isAutoDelete; - _arguments = arguments; - } + public RecordedExchange(string name, string type, bool durable, bool isAutoDelete, IDictionary? arguments) + { + _name = name; + _type = type; + _durable = durable; + _isAutoDelete = isAutoDelete; + _arguments = arguments; + } - public void Recover(IModel model) - { - model.ExchangeDeclare(Name, _type, _durable, IsAutoDelete, _arguments); - } + public void Recover(IModel model) + { + model.ExchangeDeclare(Name, _type, _durable, IsAutoDelete, _arguments); + } - public override string ToString() - { - return $"{nameof(RecordedExchange)}: name = '{Name}', type = '{_type}', durable = {_durable}, autoDelete = {IsAutoDelete}, arguments = '{_arguments}'"; + public override string ToString() + { + return $"{nameof(RecordedExchange)}: name = '{Name}', type = '{_type}', durable = {_durable}, autoDelete = {IsAutoDelete}, arguments = '{_arguments}'"; + } } } diff --git a/projects/RabbitMQ.Client/client/impl/RecordedQueue.cs b/projects/RabbitMQ.Client/client/impl/RecordedQueue.cs index e1542c9625..cbcde46f4c 100644 --- a/projects/RabbitMQ.Client/client/impl/RecordedQueue.cs +++ b/projects/RabbitMQ.Client/client/impl/RecordedQueue.cs @@ -31,50 +31,51 @@ using System.Collections.Generic; -namespace RabbitMQ.Client.Impl; - -#nullable enable -internal readonly struct RecordedQueue +namespace RabbitMQ.Client.Impl { - private readonly string _name; - private readonly IDictionary? _arguments; - private readonly bool _durable; - private readonly bool _exclusive; - private readonly bool _isAutoDelete; - private readonly bool _isServerNamed; +#nullable enable + internal readonly struct RecordedQueue + { + private readonly string _name; + private readonly IDictionary? _arguments; + private readonly bool _durable; + private readonly bool _exclusive; + private readonly bool _isAutoDelete; + private readonly bool _isServerNamed; - public string Name => _name; - public bool IsAutoDelete => _isAutoDelete; - public bool IsServerNamed => _isServerNamed; + public string Name => _name; + public bool IsAutoDelete => _isAutoDelete; + public bool IsServerNamed => _isServerNamed; - public RecordedQueue(string name, bool isServerNamed, bool durable, bool exclusive, bool autoDelete, IDictionary? arguments) - { - _name = name; - _isServerNamed = isServerNamed; - _durable = durable; - _exclusive = exclusive; - _isAutoDelete = autoDelete; - _arguments = arguments; - } + public RecordedQueue(string name, bool isServerNamed, bool durable, bool exclusive, bool autoDelete, IDictionary? arguments) + { + _name = name; + _isServerNamed = isServerNamed; + _durable = durable; + _exclusive = exclusive; + _isAutoDelete = autoDelete; + _arguments = arguments; + } - public RecordedQueue(string newName, in RecordedQueue old) - { - _name = newName; - _isServerNamed = old._isServerNamed; - _durable = old._durable; - _exclusive = old._exclusive; - _isAutoDelete = old._isAutoDelete; - _arguments = old._arguments; - } + public RecordedQueue(string newName, in RecordedQueue old) + { + _name = newName; + _isServerNamed = old._isServerNamed; + _durable = old._durable; + _exclusive = old._exclusive; + _isAutoDelete = old._isAutoDelete; + _arguments = old._arguments; + } - public string Recover(IModel channel) - { - var queueName = IsServerNamed ? string.Empty : Name; - return channel.QueueDeclare(queueName, _durable, _exclusive, IsAutoDelete, _arguments).QueueName; - } + public string Recover(IModel channel) + { + var queueName = IsServerNamed ? string.Empty : Name; + return channel.QueueDeclare(queueName, _durable, _exclusive, IsAutoDelete, _arguments).QueueName; + } - public override string ToString() - { - return $"{nameof(RecordedQueue)}: name = '{Name}', durable = {_durable}, exclusive = {_exclusive}, autoDelete = {IsAutoDelete}, arguments = '{_arguments}'"; + public override string ToString() + { + return $"{nameof(RecordedQueue)}: name = '{Name}', durable = {_durable}, exclusive = {_exclusive}, autoDelete = {IsAutoDelete}, arguments = '{_arguments}'"; + } } } diff --git a/projects/RabbitMQ.Client/client/impl/RecoveryAwareModel.cs b/projects/RabbitMQ.Client/client/impl/RecoveryAwareModel.cs index d335dc97d6..8a0d0105f3 100644 --- a/projects/RabbitMQ.Client/client/impl/RecoveryAwareModel.cs +++ b/projects/RabbitMQ.Client/client/impl/RecoveryAwareModel.cs @@ -32,60 +32,61 @@ using RabbitMQ.Client.client.impl; using RabbitMQ.Client.Framing.Impl; -namespace RabbitMQ.Client.Impl; - -internal sealed class RecoveryAwareModel : Model +namespace RabbitMQ.Client.Impl { - public RecoveryAwareModel(ConnectionConfig config, ISession session) : base(config, session) + internal sealed class RecoveryAwareModel : Model { - ActiveDeliveryTagOffset = 0; - MaxSeenDeliveryTag = 0; - } + public RecoveryAwareModel(ConnectionConfig config, ISession session) : base(config, session) + { + ActiveDeliveryTagOffset = 0; + MaxSeenDeliveryTag = 0; + } - public ulong ActiveDeliveryTagOffset { get; private set; } - public ulong MaxSeenDeliveryTag { get; private set; } + public ulong ActiveDeliveryTagOffset { get; private set; } + public ulong MaxSeenDeliveryTag { get; private set; } - internal void TakeOver(RecoveryAwareModel other) - { - base.TakeOver(other); + internal void TakeOver(RecoveryAwareModel other) + { + base.TakeOver(other); - ActiveDeliveryTagOffset = other.ActiveDeliveryTagOffset + other.MaxSeenDeliveryTag; - MaxSeenDeliveryTag = 0; - } + ActiveDeliveryTagOffset = other.ActiveDeliveryTagOffset + other.MaxSeenDeliveryTag; + MaxSeenDeliveryTag = 0; + } - protected override ulong AdjustDeliveryTag(ulong deliveryTag) - { - if (deliveryTag > MaxSeenDeliveryTag) + protected override ulong AdjustDeliveryTag(ulong deliveryTag) { - MaxSeenDeliveryTag = deliveryTag; + if (deliveryTag > MaxSeenDeliveryTag) + { + MaxSeenDeliveryTag = deliveryTag; + } + return deliveryTag + ActiveDeliveryTagOffset; } - return deliveryTag + ActiveDeliveryTagOffset; - } - public override void BasicAck(ulong deliveryTag, bool multiple) - { - ulong realTag = deliveryTag - ActiveDeliveryTagOffset; - if (realTag > 0 && realTag <= deliveryTag) + public override void BasicAck(ulong deliveryTag, bool multiple) { - base.BasicAck(realTag, multiple); + ulong realTag = deliveryTag - ActiveDeliveryTagOffset; + if (realTag > 0 && realTag <= deliveryTag) + { + base.BasicAck(realTag, multiple); + } } - } - public override void BasicNack(ulong deliveryTag, bool multiple, bool requeue) - { - ulong realTag = deliveryTag - ActiveDeliveryTagOffset; - if (realTag > 0 && realTag <= deliveryTag) + public override void BasicNack(ulong deliveryTag, bool multiple, bool requeue) { - base.BasicNack(realTag, multiple, requeue); + ulong realTag = deliveryTag - ActiveDeliveryTagOffset; + if (realTag > 0 && realTag <= deliveryTag) + { + base.BasicNack(realTag, multiple, requeue); + } } - } - public override void BasicReject(ulong deliveryTag, bool requeue) - { - ulong realTag = deliveryTag - ActiveDeliveryTagOffset; - if (realTag > 0 && realTag <= deliveryTag) + public override void BasicReject(ulong deliveryTag, bool requeue) { - base.BasicReject(realTag, requeue); + ulong realTag = deliveryTag - ActiveDeliveryTagOffset; + if (realTag > 0 && realTag <= deliveryTag) + { + base.BasicReject(realTag, requeue); + } } } } diff --git a/projects/RabbitMQ.Client/client/impl/RpcContinuationQueue.cs b/projects/RabbitMQ.Client/client/impl/RpcContinuationQueue.cs index 17378af3eb..6c8e2ee194 100644 --- a/projects/RabbitMQ.Client/client/impl/RpcContinuationQueue.cs +++ b/projects/RabbitMQ.Client/client/impl/RpcContinuationQueue.cs @@ -32,80 +32,81 @@ using System; using System.Threading; -namespace RabbitMQ.Client.Impl; - -///Manages a queue of waiting AMQP RPC requests. -/// -/// -/// Currently, pipelining of requests is forbidden by this -/// implementation. The AMQP 0-8 and 0-9 specifications themselves -/// forbid pipelining, but only by the skin of their teeth and -/// under a somewhat generous reading. -/// -/// -internal class RpcContinuationQueue +namespace RabbitMQ.Client.Impl { - private class EmptyRpcContinuation : IRpcContinuation + ///Manages a queue of waiting AMQP RPC requests. + /// + /// + /// Currently, pipelining of requests is forbidden by this + /// implementation. The AMQP 0-8 and 0-9 specifications themselves + /// forbid pipelining, but only by the skin of their teeth and + /// under a somewhat generous reading. + /// + /// + internal class RpcContinuationQueue { - public void HandleCommand(in IncomingCommand cmd) + private class EmptyRpcContinuation : IRpcContinuation { - } + public void HandleCommand(in IncomingCommand cmd) + { + } - public void HandleModelShutdown(ShutdownEventArgs reason) - { + public void HandleModelShutdown(ShutdownEventArgs reason) + { + } } - } - private static readonly EmptyRpcContinuation s_tmp = new EmptyRpcContinuation(); - private IRpcContinuation _outstandingRpc = s_tmp; + private static readonly EmptyRpcContinuation s_tmp = new EmptyRpcContinuation(); + private IRpcContinuation _outstandingRpc = s_tmp; - ///Enqueue a continuation, marking a pending RPC. - /// - /// - /// Continuations are retrieved in FIFO order by calling Next(). - /// - /// - /// In the current implementation, only one continuation can - /// be queued up at once. Calls to Enqueue() when a - /// continuation is already enqueued will result in - /// NotSupportedException being thrown. - /// - /// - public void Enqueue(IRpcContinuation k) - { - IRpcContinuation result = Interlocked.CompareExchange(ref _outstandingRpc, k, s_tmp); - if (!(result is EmptyRpcContinuation)) + ///Enqueue a continuation, marking a pending RPC. + /// + /// + /// Continuations are retrieved in FIFO order by calling Next(). + /// + /// + /// In the current implementation, only one continuation can + /// be queued up at once. Calls to Enqueue() when a + /// continuation is already enqueued will result in + /// NotSupportedException being thrown. + /// + /// + public void Enqueue(IRpcContinuation k) { - throw new NotSupportedException("Pipelining of requests forbidden"); + IRpcContinuation result = Interlocked.CompareExchange(ref _outstandingRpc, k, s_tmp); + if (!(result is EmptyRpcContinuation)) + { + throw new NotSupportedException("Pipelining of requests forbidden"); + } } - } - ///Interrupt all waiting continuations. - /// - /// - /// There's just the one potential waiter in the current - /// implementation. - /// - /// - public void HandleModelShutdown(ShutdownEventArgs reason) - { - Next().HandleModelShutdown(reason); - } + ///Interrupt all waiting continuations. + /// + /// + /// There's just the one potential waiter in the current + /// implementation. + /// + /// + public void HandleModelShutdown(ShutdownEventArgs reason) + { + Next().HandleModelShutdown(reason); + } - ///Retrieve the next waiting continuation. - /// - /// - /// It is an error to call this method when there are no - /// waiting continuations. In the current implementation, if - /// this happens, null will be returned (which will usually - /// result in an immediate NullPointerException in the - /// caller). Correct code will always arrange for a - /// continuation to have been Enqueue()d before calling this - /// method. - /// - /// - public IRpcContinuation Next() - { - return Interlocked.Exchange(ref _outstandingRpc, s_tmp); + ///Retrieve the next waiting continuation. + /// + /// + /// It is an error to call this method when there are no + /// waiting continuations. In the current implementation, if + /// this happens, null will be returned (which will usually + /// result in an immediate NullPointerException in the + /// caller). Correct code will always arrange for a + /// continuation to have been Enqueue()d before calling this + /// method. + /// + /// + public IRpcContinuation Next() + { + return Interlocked.Exchange(ref _outstandingRpc, s_tmp); + } } } diff --git a/projects/RabbitMQ.Client/client/impl/Session.cs b/projects/RabbitMQ.Client/client/impl/Session.cs index ab30d8f05e..d724fe3cca 100644 --- a/projects/RabbitMQ.Client/client/impl/Session.cs +++ b/projects/RabbitMQ.Client/client/impl/Session.cs @@ -31,27 +31,28 @@ using RabbitMQ.Client.Framing.Impl; -namespace RabbitMQ.Client.Impl; - -///Normal ISession implementation used during normal channel operation. -internal class Session : SessionBase +namespace RabbitMQ.Client.Impl { - private readonly CommandAssembler _assembler; - - public Session(Connection connection, ushort channelNumber) : base(connection, channelNumber) - { - _assembler = new CommandAssembler(); - } - - public override bool HandleFrame(in InboundFrame frame) + ///Normal ISession implementation used during normal channel operation. + internal class Session : SessionBase { - bool shallReturnFramePayload = _assembler.HandleFrame(in frame, out IncomingCommand cmd); + private readonly CommandAssembler _assembler; - if (!cmd.IsEmpty) + public Session(Connection connection, ushort channelNumber) : base(connection, channelNumber) { - CommandReceived.Invoke(in cmd); + _assembler = new CommandAssembler(); } - return shallReturnFramePayload; + public override bool HandleFrame(in InboundFrame frame) + { + bool shallReturnFramePayload = _assembler.HandleFrame(in frame, out IncomingCommand cmd); + + if (!cmd.IsEmpty) + { + CommandReceived.Invoke(in cmd); + } + + return shallReturnFramePayload; + } } } diff --git a/projects/RabbitMQ.Client/client/impl/SessionBase.cs b/projects/RabbitMQ.Client/client/impl/SessionBase.cs index ff605f938d..c6991f5c70 100644 --- a/projects/RabbitMQ.Client/client/impl/SessionBase.cs +++ b/projects/RabbitMQ.Client/client/impl/SessionBase.cs @@ -36,121 +36,122 @@ using RabbitMQ.Client.Framing.Impl; using RabbitMQ.Client.Logging; -namespace RabbitMQ.Client.Impl; - -internal abstract class SessionBase : ISession +namespace RabbitMQ.Client.Impl { - private ShutdownEventArgs _closeReason; - public ShutdownEventArgs CloseReason => Volatile.Read(ref _closeReason); - - protected SessionBase(Connection connection, ushort channelNumber) + internal abstract class SessionBase : ISession { - Connection = connection; - ChannelNumber = channelNumber; - if (channelNumber != 0) + private ShutdownEventArgs _closeReason; + public ShutdownEventArgs CloseReason => Volatile.Read(ref _closeReason); + + protected SessionBase(Connection connection, ushort channelNumber) { - connection.ConnectionShutdown += OnConnectionShutdown; + Connection = connection; + ChannelNumber = channelNumber; + if (channelNumber != 0) + { + connection.ConnectionShutdown += OnConnectionShutdown; + } + RabbitMqClientEventSource.Log.ChannelOpened(); } - RabbitMqClientEventSource.Log.ChannelOpened(); - } - public event EventHandler SessionShutdown - { - add + public event EventHandler SessionShutdown { - if (CloseReason is null) + add { - _sessionShutdownWrapper.AddHandler(value); + if (CloseReason is null) + { + _sessionShutdownWrapper.AddHandler(value); + } + else + { + value(this, CloseReason); + } } - else + remove { - value(this, CloseReason); + _sessionShutdownWrapper.RemoveHandler(value); } } - remove - { - _sessionShutdownWrapper.RemoveHandler(value); - } - } - private EventingWrapper _sessionShutdownWrapper; + private EventingWrapper _sessionShutdownWrapper; - public ushort ChannelNumber { get; } + public ushort ChannelNumber { get; } - public CommandReceivedAction CommandReceived { get; set; } - public Connection Connection { get; } + public CommandReceivedAction CommandReceived { get; set; } + public Connection Connection { get; } - public bool IsOpen => CloseReason is null; - - public virtual void OnConnectionShutdown(object conn, ShutdownEventArgs reason) - { - Close(reason); - } + public bool IsOpen => CloseReason is null; - public virtual void OnSessionShutdown(ShutdownEventArgs reason) - { - Connection.ConnectionShutdown -= OnConnectionShutdown; - _sessionShutdownWrapper.Invoke(this, reason); - } - - public override string ToString() - { - return $"{GetType().Name}#{ChannelNumber}:{Connection}"; - } - - public void Close(ShutdownEventArgs reason) - { - Close(reason, true); - } + public virtual void OnConnectionShutdown(object conn, ShutdownEventArgs reason) + { + Close(reason); + } - public void Close(ShutdownEventArgs reason, bool notify) - { - if (Interlocked.CompareExchange(ref _closeReason, reason, null) is null) + public virtual void OnSessionShutdown(ShutdownEventArgs reason) { - RabbitMqClientEventSource.Log.ChannelClosed(); + Connection.ConnectionShutdown -= OnConnectionShutdown; + _sessionShutdownWrapper.Invoke(this, reason); } - if (notify) + + public override string ToString() { - OnSessionShutdown(CloseReason); + return $"{GetType().Name}#{ChannelNumber}:{Connection}"; } - } - public abstract bool HandleFrame(in InboundFrame frame); + public void Close(ShutdownEventArgs reason) + { + Close(reason, true); + } - public void Notify() - { - // Ensure that we notify only when session is already closed - // If not, throw exception, since this is a serious bug in the library - var reason = CloseReason; - if (reason is null) + public void Close(ShutdownEventArgs reason, bool notify) { - throw new Exception("Internal Error in Session.Close"); + if (Interlocked.CompareExchange(ref _closeReason, reason, null) is null) + { + RabbitMqClientEventSource.Log.ChannelClosed(); + } + if (notify) + { + OnSessionShutdown(CloseReason); + } } - OnSessionShutdown(reason); - } + public abstract bool HandleFrame(in InboundFrame frame); - public virtual void Transmit(ref T cmd) where T : struct, IOutgoingAmqpMethod - { - if (!IsOpen && cmd.ProtocolCommandId != client.framing.ProtocolCommandId.ChannelCloseOk) + public void Notify() { - ThrowAlreadyClosedException(); + // Ensure that we notify only when session is already closed + // If not, throw exception, since this is a serious bug in the library + var reason = CloseReason; + if (reason is null) + { + throw new Exception("Internal Error in Session.Close"); + } + + OnSessionShutdown(reason); } - Connection.Write(Framing.SerializeToFrames(ref cmd, ChannelNumber)); - } + public virtual void Transmit(ref T cmd) where T : struct, IOutgoingAmqpMethod + { + if (!IsOpen && cmd.ProtocolCommandId != client.framing.ProtocolCommandId.ChannelCloseOk) + { + ThrowAlreadyClosedException(); + } - public void Transmit(ref TMethod cmd, ref THeader header, ReadOnlyMemory body) - where TMethod : struct, IOutgoingAmqpMethod - where THeader : IAmqpHeader - { - if (!IsOpen && cmd.ProtocolCommandId != ProtocolCommandId.ChannelCloseOk) + Connection.Write(Framing.SerializeToFrames(ref cmd, ChannelNumber)); + } + + public void Transmit(ref TMethod cmd, ref THeader header, ReadOnlyMemory body) + where TMethod : struct, IOutgoingAmqpMethod + where THeader : IAmqpHeader { - ThrowAlreadyClosedException(); + if (!IsOpen && cmd.ProtocolCommandId != ProtocolCommandId.ChannelCloseOk) + { + ThrowAlreadyClosedException(); + } + + Connection.Write(Framing.SerializeToFrames(ref cmd, ref header, body, ChannelNumber, Connection.MaxPayloadSize)); } - Connection.Write(Framing.SerializeToFrames(ref cmd, ref header, body, ChannelNumber, Connection.MaxPayloadSize)); + private void ThrowAlreadyClosedException() + => throw new AlreadyClosedException(CloseReason); } - - private void ThrowAlreadyClosedException() - => throw new AlreadyClosedException(CloseReason); } diff --git a/projects/RabbitMQ.Client/client/impl/SessionManager.cs b/projects/RabbitMQ.Client/client/impl/SessionManager.cs index 93d1a1ba6e..a3071e472a 100644 --- a/projects/RabbitMQ.Client/client/impl/SessionManager.cs +++ b/projects/RabbitMQ.Client/client/impl/SessionManager.cs @@ -34,65 +34,66 @@ using RabbitMQ.Client.Framing.Impl; using RabbitMQ.Util; -namespace RabbitMQ.Client.Impl; - -internal class SessionManager +namespace RabbitMQ.Client.Impl { - public readonly ushort ChannelMax; - private readonly IntAllocator _ints; - private readonly Connection _connection; - private readonly Dictionary _sessionMap = new Dictionary(); - - public SessionManager(Connection connection, ushort channelMax) + internal class SessionManager { - _connection = connection; - ChannelMax = (channelMax == 0) ? ushort.MaxValue : channelMax; - _ints = new IntAllocator(1, ChannelMax); - } + public readonly ushort ChannelMax; + private readonly IntAllocator _ints; + private readonly Connection _connection; + private readonly Dictionary _sessionMap = new Dictionary(); - public int Count - { - get + public SessionManager(Connection connection, ushort channelMax) { - lock (_sessionMap) + _connection = connection; + ChannelMax = (channelMax == 0) ? ushort.MaxValue : channelMax; + _ints = new IntAllocator(1, ChannelMax); + } + + public int Count + { + get { - return _sessionMap.Count; + lock (_sessionMap) + { + return _sessionMap.Count; + } } } - } - public ISession Create() - { - lock (_sessionMap) + public ISession Create() { - int channelNumber = _ints.Allocate(); - if (channelNumber == -1) + lock (_sessionMap) { - throw new ChannelAllocationException(); - } + int channelNumber = _ints.Allocate(); + if (channelNumber == -1) + { + throw new ChannelAllocationException(); + } - ISession session = new Session(_connection, (ushort)channelNumber); - session.SessionShutdown += HandleSessionShutdown; - _sessionMap[channelNumber] = session; - return session; + ISession session = new Session(_connection, (ushort)channelNumber); + session.SessionShutdown += HandleSessionShutdown; + _sessionMap[channelNumber] = session; + return session; + } } - } - private void HandleSessionShutdown(object sender, ShutdownEventArgs reason) - { - lock (_sessionMap) + private void HandleSessionShutdown(object sender, ShutdownEventArgs reason) { - var session = (ISession)sender; - _sessionMap.Remove(session.ChannelNumber); - _ints.Free(session.ChannelNumber); + lock (_sessionMap) + { + var session = (ISession)sender; + _sessionMap.Remove(session.ChannelNumber); + _ints.Free(session.ChannelNumber); + } } - } - public ISession Lookup(int number) - { - lock (_sessionMap) + public ISession Lookup(int number) { - return _sessionMap[number]; + lock (_sessionMap) + { + return _sessionMap[number]; + } } } } diff --git a/projects/RabbitMQ.Client/client/impl/ShutdownContinuation.cs b/projects/RabbitMQ.Client/client/impl/ShutdownContinuation.cs index a35ca550f1..443222789a 100644 --- a/projects/RabbitMQ.Client/client/impl/ShutdownContinuation.cs +++ b/projects/RabbitMQ.Client/client/impl/ShutdownContinuation.cs @@ -33,39 +33,40 @@ using RabbitMQ.Util; -namespace RabbitMQ.Client.Impl; - -internal class ShutdownContinuation +namespace RabbitMQ.Client.Impl { - public readonly BlockingCell m_cell = new BlockingCell(); + internal class ShutdownContinuation + { + public readonly BlockingCell m_cell = new BlockingCell(); - // You will note there are two practically identical overloads - // of OnShutdown() here. This is because Microsoft's C# - // compilers do not consistently support the Liskov - // substitutability principle. When I use - // OnShutdown(object,ShutdownEventArgs), the compilers - // complain that OnShutdown can't be placed into a - // ConnectionShutdownEventHandler because object doesn't - // "match" IConnection, even though there's no context in - // which the program could Go Wrong were it to accept the - // code. The same problem appears for - // ModelShutdownEventHandler. The .NET 1.1 compiler complains - // about these two cases, and the .NET 2.0 compiler does not - - // presumably they improved the type checker with the new - // release of the compiler. + // You will note there are two practically identical overloads + // of OnShutdown() here. This is because Microsoft's C# + // compilers do not consistently support the Liskov + // substitutability principle. When I use + // OnShutdown(object,ShutdownEventArgs), the compilers + // complain that OnShutdown can't be placed into a + // ConnectionShutdownEventHandler because object doesn't + // "match" IConnection, even though there's no context in + // which the program could Go Wrong were it to accept the + // code. The same problem appears for + // ModelShutdownEventHandler. The .NET 1.1 compiler complains + // about these two cases, and the .NET 2.0 compiler does not - + // presumably they improved the type checker with the new + // release of the compiler. - public virtual void OnConnectionShutdown(object sender, ShutdownEventArgs reason) - { - m_cell.ContinueWithValue(reason); - } + public virtual void OnConnectionShutdown(object sender, ShutdownEventArgs reason) + { + m_cell.ContinueWithValue(reason); + } - public virtual ShutdownEventArgs Wait() - { - return m_cell.WaitForValue(); - } + public virtual ShutdownEventArgs Wait() + { + return m_cell.WaitForValue(); + } - public ShutdownEventArgs Wait(TimeSpan timeout) - { - return m_cell.WaitForValue(timeout); + public ShutdownEventArgs Wait(TimeSpan timeout) + { + return m_cell.WaitForValue(timeout); + } } } diff --git a/projects/RabbitMQ.Client/client/impl/SimpleBlockingRpcContinuation.cs b/projects/RabbitMQ.Client/client/impl/SimpleBlockingRpcContinuation.cs index d8d373bd33..c2c1b3fa5d 100644 --- a/projects/RabbitMQ.Client/client/impl/SimpleBlockingRpcContinuation.cs +++ b/projects/RabbitMQ.Client/client/impl/SimpleBlockingRpcContinuation.cs @@ -33,45 +33,46 @@ using RabbitMQ.Client.Exceptions; using RabbitMQ.Util; -namespace RabbitMQ.Client.Impl; - -internal class SimpleBlockingRpcContinuation : IRpcContinuation +namespace RabbitMQ.Client.Impl { - private readonly BlockingCell> m_cell = new BlockingCell>(); - - public void GetReply(TimeSpan timeout) + internal class SimpleBlockingRpcContinuation : IRpcContinuation { - Either result = m_cell.WaitForValue(timeout); - if (result.Alternative == EitherAlternative.Left) + private readonly BlockingCell> m_cell = new BlockingCell>(); + + public void GetReply(TimeSpan timeout) { - return; + Either result = m_cell.WaitForValue(timeout); + if (result.Alternative == EitherAlternative.Left) + { + return; + } + ThrowOperationInterruptedException(result.RightValue); } - ThrowOperationInterruptedException(result.RightValue); - } - public void GetReply(TimeSpan timeout, out IncomingCommand reply) - { - Either result = m_cell.WaitForValue(timeout); - if (result.Alternative == EitherAlternative.Left) + public void GetReply(TimeSpan timeout, out IncomingCommand reply) { - reply = result.LeftValue; - return; - } + Either result = m_cell.WaitForValue(timeout); + if (result.Alternative == EitherAlternative.Left) + { + reply = result.LeftValue; + return; + } - reply = IncomingCommand.Empty; - ThrowOperationInterruptedException(result.RightValue); - } + reply = IncomingCommand.Empty; + ThrowOperationInterruptedException(result.RightValue); + } - private static void ThrowOperationInterruptedException(ShutdownEventArgs shutdownEventArgs) - => throw new OperationInterruptedException(shutdownEventArgs); + private static void ThrowOperationInterruptedException(ShutdownEventArgs shutdownEventArgs) + => throw new OperationInterruptedException(shutdownEventArgs); - public void HandleCommand(in IncomingCommand cmd) - { - m_cell.ContinueWithValue(Either.Left(cmd)); - } + public void HandleCommand(in IncomingCommand cmd) + { + m_cell.ContinueWithValue(Either.Left(cmd)); + } - public void HandleModelShutdown(ShutdownEventArgs reason) - { - m_cell.ContinueWithValue(Either.Right(reason)); + public void HandleModelShutdown(ShutdownEventArgs reason) + { + m_cell.ContinueWithValue(Either.Right(reason)); + } } } diff --git a/projects/RabbitMQ.Client/client/impl/SocketFrameHandler.cs b/projects/RabbitMQ.Client/client/impl/SocketFrameHandler.cs index c5fb7577e1..3dd6bc6c66 100644 --- a/projects/RabbitMQ.Client/client/impl/SocketFrameHandler.cs +++ b/projects/RabbitMQ.Client/client/impl/SocketFrameHandler.cs @@ -41,326 +41,323 @@ using RabbitMQ.Client.Exceptions; using RabbitMQ.Client.Logging; -namespace RabbitMQ.Client.Impl; - -internal static class TaskExtensions +namespace RabbitMQ.Client.Impl { - public static async Task TimeoutAfter(this Task task, TimeSpan timeout) + internal static class TaskExtensions { -#if NET6_0_OR_GREATER - await task.WaitAsync(timeout).ConfigureAwait(false); -#else - if (task == await Task.WhenAny(task, Task.Delay(timeout)).ConfigureAwait(false)) + public static async Task TimeoutAfter(this Task task, TimeSpan timeout) { - await task.ConfigureAwait(false); - } - else - { - Task supressErrorTask = task.ContinueWith((t, s) => t.Exception.Handle(e => true), null, CancellationToken.None, TaskContinuationOptions.OnlyOnFaulted | TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); - throw new TimeoutException(); + if (task == await Task.WhenAny(task, Task.Delay(timeout)).ConfigureAwait(false)) + { + await task.ConfigureAwait(false); + } + else + { + Task supressErrorTask = task.ContinueWith((t, s) => t.Exception.Handle(e => true), null, CancellationToken.None, TaskContinuationOptions.OnlyOnFaulted | TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); + throw new TimeoutException(); + } } -#endif } -} -internal sealed class SocketFrameHandler : IFrameHandler -{ - private readonly ITcpClient _socket; - private readonly Stream _reader; - private readonly Stream _writer; - private readonly ChannelWriter> _channelWriter; - private readonly ChannelReader> _channelReader; - private readonly Task _writerTask; - private readonly object _semaphore = new object(); - private readonly byte[] _frameHeaderBuffer; - private bool _closed; - - public SocketFrameHandler(AmqpTcpEndpoint endpoint, - Func socketFactory, - TimeSpan connectionTimeout, TimeSpan readTimeout, TimeSpan writeTimeout) + internal sealed class SocketFrameHandler : IFrameHandler { - Endpoint = endpoint; - _frameHeaderBuffer = new byte[7]; - var channel = Channel.CreateUnbounded>( - new UnboundedChannelOptions - { - AllowSynchronousContinuations = false, - SingleReader = true, - SingleWriter = false - }); + private readonly ITcpClient _socket; + private readonly Stream _reader; + private readonly Stream _writer; + private readonly ChannelWriter> _channelWriter; + private readonly ChannelReader> _channelReader; + private readonly Task _writerTask; + private readonly object _semaphore = new object(); + private readonly byte[] _frameHeaderBuffer; + private bool _closed; + + public SocketFrameHandler(AmqpTcpEndpoint endpoint, + Func socketFactory, + TimeSpan connectionTimeout, TimeSpan readTimeout, TimeSpan writeTimeout) + { + Endpoint = endpoint; + _frameHeaderBuffer = new byte[7]; + var channel = Channel.CreateUnbounded>( + new UnboundedChannelOptions + { + AllowSynchronousContinuations = false, + SingleReader = true, + SingleWriter = false + }); - _channelReader = channel.Reader; - _channelWriter = channel.Writer; + _channelReader = channel.Reader; + _channelWriter = channel.Writer; - // Resolve the hostname to know if it's even possible to even try IPv6 - IPAddress[] adds = Dns.GetHostAddresses(endpoint.HostName); - IPAddress ipv6 = TcpClientAdapterHelper.GetMatchingHost(adds, AddressFamily.InterNetworkV6); + // Resolve the hostname to know if it's even possible to even try IPv6 + IPAddress[] adds = Dns.GetHostAddresses(endpoint.HostName); + IPAddress ipv6 = TcpClientAdapterHelper.GetMatchingHost(adds, AddressFamily.InterNetworkV6); - if (ipv6 == default(IPAddress)) - { - if (endpoint.AddressFamily == AddressFamily.InterNetworkV6) + if (ipv6 == default(IPAddress)) { - throw new ConnectFailureException("Connection failed", new ArgumentException($"No IPv6 address could be resolved for {endpoint.HostName}")); - } - } - else if (ShouldTryIPv6(endpoint)) - { - try - { - _socket = ConnectUsingIPv6(new IPEndPoint(ipv6, endpoint.Port), socketFactory, connectionTimeout); + if (endpoint.AddressFamily == AddressFamily.InterNetworkV6) + { + throw new ConnectFailureException("Connection failed", new ArgumentException($"No IPv6 address could be resolved for {endpoint.HostName}")); + } } - catch (ConnectFailureException) + else if (ShouldTryIPv6(endpoint)) { - // We resolved to a ipv6 address and tried it but it still didn't connect, try IPv4 - _socket = null; + try + { + _socket = ConnectUsingIPv6(new IPEndPoint(ipv6, endpoint.Port), socketFactory, connectionTimeout); + } + catch (ConnectFailureException) + { + // We resolved to a ipv6 address and tried it but it still didn't connect, try IPv4 + _socket = null; + } } - } - if (_socket is null) - { - IPAddress ipv4 = TcpClientAdapterHelper.GetMatchingHost(adds, AddressFamily.InterNetwork); - if (ipv4 == default(IPAddress)) + if (_socket is null) { - throw new ConnectFailureException("Connection failed", new ArgumentException($"No ip address could be resolved for {endpoint.HostName}")); + IPAddress ipv4 = TcpClientAdapterHelper.GetMatchingHost(adds, AddressFamily.InterNetwork); + if (ipv4 == default(IPAddress)) + { + throw new ConnectFailureException("Connection failed", new ArgumentException($"No ip address could be resolved for {endpoint.HostName}")); + } + _socket = ConnectUsingIPv4(new IPEndPoint(ipv4, endpoint.Port), socketFactory, connectionTimeout); } - _socket = ConnectUsingIPv4(new IPEndPoint(ipv4, endpoint.Port), socketFactory, connectionTimeout); - } - Stream netstream = _socket.GetStream(); - netstream.ReadTimeout = (int)readTimeout.TotalMilliseconds; - netstream.WriteTimeout = (int)writeTimeout.TotalMilliseconds; + Stream netstream = _socket.GetStream(); + netstream.ReadTimeout = (int)readTimeout.TotalMilliseconds; + netstream.WriteTimeout = (int)writeTimeout.TotalMilliseconds; - if (endpoint.Ssl.Enabled) - { - try - { - netstream = SslHelper.TcpUpgrade(netstream, endpoint.Ssl); - } - catch (Exception) + if (endpoint.Ssl.Enabled) { - Close(); - throw; + try + { + netstream = SslHelper.TcpUpgrade(netstream, endpoint.Ssl); + } + catch (Exception) + { + Close(); + throw; + } } - } - - _reader = new BufferedStream(netstream, _socket.Client.ReceiveBufferSize); - _writer = new BufferedStream(netstream, _socket.Client.SendBufferSize); - WriteTimeout = writeTimeout; - _writerTask = Task.Run(WriteLoop); - } - public AmqpTcpEndpoint Endpoint { get; set; } + _reader = new BufferedStream(netstream, _socket.Client.ReceiveBufferSize); + _writer = new BufferedStream(netstream, _socket.Client.SendBufferSize); - public EndPoint LocalEndPoint - { - get { return _socket.Client.LocalEndPoint; } - } - - public int LocalPort - { - get { return ((IPEndPoint)LocalEndPoint).Port; } - } + WriteTimeout = writeTimeout; + _writerTask = Task.Run(WriteLoop); + } + public AmqpTcpEndpoint Endpoint { get; set; } - public EndPoint RemoteEndPoint - { - get { return _socket.Client.RemoteEndPoint; } - } + public EndPoint LocalEndPoint + { + get { return _socket.Client.LocalEndPoint; } + } - public int RemotePort - { - get { return ((IPEndPoint)RemoteEndPoint).Port; } - } + public int LocalPort + { + get { return ((IPEndPoint)LocalEndPoint).Port; } + } - public TimeSpan ReadTimeout - { - set + public EndPoint RemoteEndPoint { - try - { - if (_socket.Connected) - { - _socket.ReceiveTimeout = value; - } - } - catch (SocketException) - { - // means that the socket is already closed - } + get { return _socket.Client.RemoteEndPoint; } } - } - public TimeSpan WriteTimeout - { - set + public int RemotePort { - _socket.Client.SendTimeout = (int)value.TotalMilliseconds; + get { return ((IPEndPoint)RemoteEndPoint).Port; } } - } - public void Close() - { - lock (_semaphore) + public TimeSpan ReadTimeout { - if (_closed || _socket == null) - { - return; - } - else + set { try { - _channelWriter.Complete(); - _writerTask?.GetAwaiter().GetResult(); + if (_socket.Connected) + { + _socket.ReceiveTimeout = value; + } } - catch + catch (SocketException) { - // ignore, we are closing anyway + // means that the socket is already closed } + } + } - try - { - _socket.Close(); - } - catch + public TimeSpan WriteTimeout + { + set + { + _socket.Client.SendTimeout = (int)value.TotalMilliseconds; + } + } + + public void Close() + { + lock (_semaphore) + { + if (_closed || _socket == null) { - // ignore, we are closing anyway + return; } - finally + else { - _closed = true; + try + { + _channelWriter.Complete(); + _writerTask?.GetAwaiter().GetResult(); + } + catch + { + // ignore, we are closing anyway + } + + try + { + _socket.Close(); + } + catch + { + // ignore, we are closing anyway + } + finally + { + _closed = true; + } } } } - } - public InboundFrame ReadFrame() - { - return InboundFrame.ReadFrom(_reader, _frameHeaderBuffer); - } + public InboundFrame ReadFrame() + { + return InboundFrame.ReadFrom(_reader, _frameHeaderBuffer); + } - public void SendHeader() - { + public void SendHeader() + { #if NETSTANDARD - var headerBytes = new byte[8]; + var headerBytes = new byte[8]; #else - Span headerBytes = stackalloc byte[8]; + Span headerBytes = stackalloc byte[8]; #endif - headerBytes[0] = (byte)'A'; - headerBytes[1] = (byte)'M'; - headerBytes[2] = (byte)'Q'; - headerBytes[3] = (byte)'P'; + headerBytes[0] = (byte)'A'; + headerBytes[1] = (byte)'M'; + headerBytes[2] = (byte)'Q'; + headerBytes[3] = (byte)'P'; - if (Endpoint.Protocol.Revision != 0) - { - headerBytes[4] = 0; - headerBytes[5] = (byte)Endpoint.Protocol.MajorVersion; - headerBytes[6] = (byte)Endpoint.Protocol.MinorVersion; - headerBytes[7] = (byte)Endpoint.Protocol.Revision; - } - else - { - headerBytes[4] = 1; - headerBytes[5] = 1; - headerBytes[6] = (byte)Endpoint.Protocol.MajorVersion; - headerBytes[7] = (byte)Endpoint.Protocol.MinorVersion; - } + if (Endpoint.Protocol.Revision != 0) + { + headerBytes[4] = 0; + headerBytes[5] = (byte)Endpoint.Protocol.MajorVersion; + headerBytes[6] = (byte)Endpoint.Protocol.MinorVersion; + headerBytes[7] = (byte)Endpoint.Protocol.Revision; + } + else + { + headerBytes[4] = 1; + headerBytes[5] = 1; + headerBytes[6] = (byte)Endpoint.Protocol.MajorVersion; + headerBytes[7] = (byte)Endpoint.Protocol.MinorVersion; + } #if NETSTANDARD - _writer.Write(headerBytes, 0, 8); + _writer.Write(headerBytes, 0, 8); #else - _writer.Write(headerBytes); + _writer.Write(headerBytes); #endif - _writer.Flush(); - } + _writer.Flush(); + } - public void Write(ReadOnlyMemory memory) - { - _channelWriter.TryWrite(memory); - } + public void Write(ReadOnlyMemory memory) + { + _channelWriter.TryWrite(memory); + } - private async Task WriteLoop() - { - while (await _channelReader.WaitToReadAsync().ConfigureAwait(false)) + private async Task WriteLoop() { - while (_channelReader.TryRead(out ReadOnlyMemory memory)) + while (await _channelReader.WaitToReadAsync().ConfigureAwait(false)) { - MemoryMarshal.TryGetArray(memory, out ArraySegment segment); + while (_channelReader.TryRead(out ReadOnlyMemory memory)) + { + MemoryMarshal.TryGetArray(memory, out ArraySegment segment); #if NETSTANDARD - await _writer.WriteAsync(segment.Array, segment.Offset, segment.Count).ConfigureAwait(false); + await _writer.WriteAsync(segment.Array, segment.Offset, segment.Count).ConfigureAwait(false); #else - await _writer.WriteAsync(memory).ConfigureAwait(false); + await _writer.WriteAsync(memory).ConfigureAwait(false); #endif - RabbitMqClientEventSource.Log.CommandSent(segment.Count); - ArrayPool.Shared.Return(segment.Array); - } + RabbitMqClientEventSource.Log.CommandSent(segment.Count); + ArrayPool.Shared.Return(segment.Array); + } - await _writer.FlushAsync().ConfigureAwait(false); + await _writer.FlushAsync().ConfigureAwait(false); + } } - } - - private static bool ShouldTryIPv6(AmqpTcpEndpoint endpoint) - { - return Socket.OSSupportsIPv6 && endpoint.AddressFamily != AddressFamily.InterNetwork; - } - - private ITcpClient ConnectUsingIPv6(IPEndPoint endpoint, - Func socketFactory, - TimeSpan timeout) - { - return ConnectUsingAddressFamily(endpoint, socketFactory, timeout, AddressFamily.InterNetworkV6); - } - - private ITcpClient ConnectUsingIPv4(IPEndPoint endpoint, - Func socketFactory, - TimeSpan timeout) - { - return ConnectUsingAddressFamily(endpoint, socketFactory, timeout, AddressFamily.InterNetwork); - } - private ITcpClient ConnectUsingAddressFamily(IPEndPoint endpoint, - Func socketFactory, - TimeSpan timeout, AddressFamily family) - { - ITcpClient socket = socketFactory(family); - try - { - ConnectOrFail(socket, endpoint, timeout); - return socket; - } - catch (ConnectFailureException) + private static bool ShouldTryIPv6(AmqpTcpEndpoint endpoint) { - socket.Dispose(); - throw; + return Socket.OSSupportsIPv6 && endpoint.AddressFamily != AddressFamily.InterNetwork; } - } - private void ConnectOrFail(ITcpClient socket, IPEndPoint endpoint, TimeSpan timeout) - { - try + private ITcpClient ConnectUsingIPv6(IPEndPoint endpoint, + Func socketFactory, + TimeSpan timeout) { - socket.ConnectAsync(endpoint.Address, endpoint.Port) - .TimeoutAfter(timeout) - .ConfigureAwait(false) - // this ensures exceptions aren't wrapped in an AggregateException - .GetAwaiter() - .GetResult(); + return ConnectUsingAddressFamily(endpoint, socketFactory, timeout, AddressFamily.InterNetworkV6); } - catch (ArgumentException e) - { - throw new ConnectFailureException("Connection failed", e); - } - catch (SocketException e) + + private ITcpClient ConnectUsingIPv4(IPEndPoint endpoint, + Func socketFactory, + TimeSpan timeout) { - throw new ConnectFailureException("Connection failed", e); + return ConnectUsingAddressFamily(endpoint, socketFactory, timeout, AddressFamily.InterNetwork); } - catch (NotSupportedException e) + + private ITcpClient ConnectUsingAddressFamily(IPEndPoint endpoint, + Func socketFactory, + TimeSpan timeout, AddressFamily family) { - throw new ConnectFailureException("Connection failed", e); + ITcpClient socket = socketFactory(family); + try + { + ConnectOrFail(socket, endpoint, timeout); + return socket; + } + catch (ConnectFailureException) + { + socket.Dispose(); + throw; + } } - catch (TimeoutException e) + + private void ConnectOrFail(ITcpClient socket, IPEndPoint endpoint, TimeSpan timeout) { - throw new ConnectFailureException("Connection failed", e); + try + { + socket.ConnectAsync(endpoint.Address, endpoint.Port) + .TimeoutAfter(timeout) + .ConfigureAwait(false) + // this ensures exceptions aren't wrapped in an AggregateException + .GetAwaiter() + .GetResult(); + } + catch (ArgumentException e) + { + throw new ConnectFailureException("Connection failed", e); + } + catch (SocketException e) + { + throw new ConnectFailureException("Connection failed", e); + } + catch (NotSupportedException e) + { + throw new ConnectFailureException("Connection failed", e); + } + catch (TimeoutException e) + { + throw new ConnectFailureException("Connection failed", e); + } } } } diff --git a/projects/RabbitMQ.Client/client/impl/SslHelper.cs b/projects/RabbitMQ.Client/client/impl/SslHelper.cs index 0a1d28a39d..beeb0a968a 100644 --- a/projects/RabbitMQ.Client/client/impl/SslHelper.cs +++ b/projects/RabbitMQ.Client/client/impl/SslHelper.cs @@ -35,81 +35,82 @@ using System.Security.Authentication; using System.Security.Cryptography.X509Certificates; -namespace RabbitMQ.Client.Impl; - -/// -/// Represents an which does the actual heavy lifting to set up an SSL connection, -/// using the config options in an to make things cleaner. -/// -internal class SslHelper +namespace RabbitMQ.Client.Impl { - private readonly SslOption _sslOption; - - private SslHelper(SslOption sslOption) - { - _sslOption = sslOption; - } - /// - /// Upgrade a Tcp stream to an Ssl stream using the TLS options provided. + /// Represents an which does the actual heavy lifting to set up an SSL connection, + /// using the config options in an to make things cleaner. /// - public static Stream TcpUpgrade(Stream tcpStream, SslOption options) + internal class SslHelper { - var helper = new SslHelper(options); - - RemoteCertificateValidationCallback remoteCertValidator = - options.CertificateValidationCallback ?? helper.CertificateValidationCallback; - LocalCertificateSelectionCallback localCertSelector = - options.CertificateSelectionCallback ?? helper.CertificateSelectionCallback; + private readonly SslOption _sslOption; - var sslStream = new SslStream(tcpStream, false, remoteCertValidator, localCertSelector); - - Action TryAuthenticating = (SslOption opts) => - { - sslStream.AuthenticateAsClientAsync(opts.ServerName, opts.Certs, opts.Version, - opts.CheckCertificateRevocation).GetAwaiter().GetResult(); - }; - try + private SslHelper(SslOption sslOption) { - TryAuthenticating(options); + _sslOption = sslOption; } - catch (ArgumentException e) when (e.ParamName == "sslProtocolType" && options.Version == SslProtocols.None) + + /// + /// Upgrade a Tcp stream to an Ssl stream using the TLS options provided. + /// + public static Stream TcpUpgrade(Stream tcpStream, SslOption options) { - // SslProtocols.None is dysfunctional in this environment, possibly due to TLS version restrictions - // in the app context, system or .NET version-specific behavior. See rabbitmq/rabbitmq-dotnet-client#764 - // for background. - options.UseFallbackTlsVersions(); - TryAuthenticating(options); - } + var helper = new SslHelper(options); - return sslStream; - } + RemoteCertificateValidationCallback remoteCertValidator = + options.CertificateValidationCallback ?? helper.CertificateValidationCallback; + LocalCertificateSelectionCallback localCertSelector = + options.CertificateSelectionCallback ?? helper.CertificateSelectionCallback; - private X509Certificate CertificateSelectionCallback(object sender, string targetHost, - X509CertificateCollection localCertificates, X509Certificate remoteCertificate, string[] acceptableIssuers) - { - if (acceptableIssuers != null && acceptableIssuers.Length > 0 && - localCertificates != null && localCertificates.Count > 0) + var sslStream = new SslStream(tcpStream, false, remoteCertValidator, localCertSelector); + + Action TryAuthenticating = (SslOption opts) => + { + sslStream.AuthenticateAsClientAsync(opts.ServerName, opts.Certs, opts.Version, + opts.CheckCertificateRevocation).GetAwaiter().GetResult(); + }; + try + { + TryAuthenticating(options); + } + catch (ArgumentException e) when (e.ParamName == "sslProtocolType" && options.Version == SslProtocols.None) + { + // SslProtocols.None is dysfunctional in this environment, possibly due to TLS version restrictions + // in the app context, system or .NET version-specific behavior. See rabbitmq/rabbitmq-dotnet-client#764 + // for background. + options.UseFallbackTlsVersions(); + TryAuthenticating(options); + } + + return sslStream; + } + + private X509Certificate CertificateSelectionCallback(object sender, string targetHost, + X509CertificateCollection localCertificates, X509Certificate remoteCertificate, string[] acceptableIssuers) { - foreach (X509Certificate certificate in localCertificates) + if (acceptableIssuers != null && acceptableIssuers.Length > 0 && + localCertificates != null && localCertificates.Count > 0) { - if (Array.IndexOf(acceptableIssuers, certificate.Issuer) != -1) + foreach (X509Certificate certificate in localCertificates) { - return certificate; + if (Array.IndexOf(acceptableIssuers, certificate.Issuer) != -1) + { + return certificate; + } } } + if (localCertificates != null && localCertificates.Count > 0) + { + return localCertificates[0]; + } + + return null; } - if (localCertificates != null && localCertificates.Count > 0) + + private bool CertificateValidationCallback(object sender, X509Certificate certificate, + X509Chain chain, SslPolicyErrors sslPolicyErrors) { - return localCertificates[0]; + return (sslPolicyErrors & ~_sslOption.AcceptablePolicyErrors) == SslPolicyErrors.None; } - - return null; - } - - private bool CertificateValidationCallback(object sender, X509Certificate certificate, - X509Chain chain, SslPolicyErrors sslPolicyErrors) - { - return (sslPolicyErrors & ~_sslOption.AcceptablePolicyErrors) == SslPolicyErrors.None; } } diff --git a/projects/RabbitMQ.Client/client/impl/TcpClientAdapter.cs b/projects/RabbitMQ.Client/client/impl/TcpClientAdapter.cs index 5e178e85f9..1f85f1967b 100644 --- a/projects/RabbitMQ.Client/client/impl/TcpClientAdapter.cs +++ b/projects/RabbitMQ.Client/client/impl/TcpClientAdapter.cs @@ -3,107 +3,108 @@ using System.Net.Sockets; using System.Threading.Tasks; -namespace RabbitMQ.Client.Impl; - -/// -/// Simple wrapper around TcpClient. -/// -internal class TcpClientAdapter : ITcpClient +namespace RabbitMQ.Client.Impl { - private Socket _sock; - - public TcpClientAdapter(Socket socket) + /// + /// Simple wrapper around TcpClient. + /// + internal class TcpClientAdapter : ITcpClient { - _sock = socket ?? throw new InvalidOperationException("socket must not be null"); - } + private Socket _sock; - public virtual async Task ConnectAsync(string host, int port) - { - AssertSocket(); - IPAddress[] adds = await Dns.GetHostAddressesAsync(host).ConfigureAwait(false); - IPAddress ep = TcpClientAdapterHelper.GetMatchingHost(adds, _sock.AddressFamily); - if (ep == default(IPAddress)) + public TcpClientAdapter(Socket socket) { - throw new ArgumentException($"No ip address could be resolved for {host}"); + _sock = socket ?? throw new InvalidOperationException("socket must not be null"); } - await ConnectAsync(ep, port).ConfigureAwait(false); - } + public virtual async Task ConnectAsync(string host, int port) + { + AssertSocket(); + IPAddress[] adds = await Dns.GetHostAddressesAsync(host).ConfigureAwait(false); + IPAddress ep = TcpClientAdapterHelper.GetMatchingHost(adds, _sock.AddressFamily); + if (ep == default(IPAddress)) + { + throw new ArgumentException($"No ip address could be resolved for {host}"); + } - public virtual Task ConnectAsync(IPAddress ep, int port) - { - AssertSocket(); - return _sock.ConnectAsync(ep, port); - } + await ConnectAsync(ep, port).ConfigureAwait(false); + } - public virtual void Close() - { - _sock?.Dispose(); - _sock = null; - } + public virtual Task ConnectAsync(IPAddress ep, int port) + { + AssertSocket(); + return _sock.ConnectAsync(ep, port); + } - [Obsolete("Override Dispose(bool) instead.")] - public virtual void Dispose() - { - Dispose(true); - } + public virtual void Close() + { + _sock?.Dispose(); + _sock = null; + } - protected virtual void Dispose(bool disposing) - { - if (disposing) + [Obsolete("Override Dispose(bool) instead.")] + public virtual void Dispose() { - // dispose managed resources - Close(); + Dispose(true); } - // dispose unmanaged resources - } + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + // dispose managed resources + Close(); + } - public virtual NetworkStream GetStream() - { - AssertSocket(); - return new NetworkStream(_sock); - } + // dispose unmanaged resources + } - public virtual Socket Client - { - get + public virtual NetworkStream GetStream() { - return _sock; + AssertSocket(); + return new NetworkStream(_sock); } - } - public virtual bool Connected - { - get + public virtual Socket Client { - if (_sock is null) + get { - return false; + return _sock; } - return _sock.Connected; } - } - public virtual TimeSpan ReceiveTimeout - { - get + public virtual bool Connected { - AssertSocket(); - return TimeSpan.FromMilliseconds(_sock.ReceiveTimeout); + get + { + if (_sock is null) + { + return false; + } + return _sock.Connected; + } } - set + + public virtual TimeSpan ReceiveTimeout { - AssertSocket(); - _sock.ReceiveTimeout = (int)value.TotalMilliseconds; + get + { + AssertSocket(); + return TimeSpan.FromMilliseconds(_sock.ReceiveTimeout); + } + set + { + AssertSocket(); + _sock.ReceiveTimeout = (int)value.TotalMilliseconds; + } } - } - private void AssertSocket() - { - if (_sock is null) + private void AssertSocket() { - throw new InvalidOperationException("Cannot perform operation as socket is null"); + if (_sock is null) + { + throw new InvalidOperationException("Cannot perform operation as socket is null"); + } } } } diff --git a/projects/RabbitMQ.Client/client/impl/TcpClientAdapterHelper.cs b/projects/RabbitMQ.Client/client/impl/TcpClientAdapterHelper.cs index f576e720d0..a9a9cf97e1 100644 --- a/projects/RabbitMQ.Client/client/impl/TcpClientAdapterHelper.cs +++ b/projects/RabbitMQ.Client/client/impl/TcpClientAdapterHelper.cs @@ -3,17 +3,18 @@ using System.Net; using System.Net.Sockets; -namespace RabbitMQ.Client.Impl; - -internal static class TcpClientAdapterHelper +namespace RabbitMQ.Client.Impl { - public static IPAddress GetMatchingHost(IReadOnlyCollection addresses, AddressFamily addressFamily) + internal static class TcpClientAdapterHelper { - IPAddress ep = addresses.FirstOrDefault(a => a.AddressFamily == addressFamily); - if (ep is null && addresses.Count == 1 && addressFamily == AddressFamily.Unspecified) + public static IPAddress GetMatchingHost(IReadOnlyCollection addresses, AddressFamily addressFamily) { - return addresses.Single(); + IPAddress ep = addresses.FirstOrDefault(a => a.AddressFamily == addressFamily); + if (ep is null && addresses.Count == 1 && addressFamily == AddressFamily.Unspecified) + { + return addresses.Single(); + } + return ep; } - return ep; } } diff --git a/projects/RabbitMQ.Client/client/impl/WireFormatting.Read.cs b/projects/RabbitMQ.Client/client/impl/WireFormatting.Read.cs index 4c86eca31f..085c052cd0 100644 --- a/projects/RabbitMQ.Client/client/impl/WireFormatting.Read.cs +++ b/projects/RabbitMQ.Client/client/impl/WireFormatting.Read.cs @@ -37,272 +37,273 @@ using RabbitMQ.Client.Exceptions; using RabbitMQ.Util; -namespace RabbitMQ.Client.Impl; - -internal static partial class WireFormatting +namespace RabbitMQ.Client.Impl { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static decimal ReadDecimal(ReadOnlySpan span) + internal static partial class WireFormatting { - byte scale = span[0]; - if (scale > 28) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static decimal ReadDecimal(ReadOnlySpan span) { - ThrowInvalidDecimalScale(scale); - } - - uint unsignedMantissa = NetworkOrderDeserializer.ReadUInt32(span.Slice(1)); - var data = new DecimalData(((uint)(scale << 16)) | unsignedMantissa & 0x80000000, 0, unsignedMantissa & 0x7FFFFFFF, 0); - return Unsafe.As(ref data); - } + byte scale = span[0]; + if (scale > 28) + { + ThrowInvalidDecimalScale(scale); + } - public static IList ReadArray(ReadOnlySpan span, out int bytesRead) - { - bytesRead = 4; - long arrayLength = NetworkOrderDeserializer.ReadUInt32(span); - if (arrayLength == 0) - { - return null; - } - List array = new List(); - while (bytesRead - 4 < arrayLength) - { - array.Add(ReadFieldValue(span.Slice(bytesRead), out int fieldValueBytesRead)); - bytesRead += fieldValueBytesRead; + uint unsignedMantissa = NetworkOrderDeserializer.ReadUInt32(span.Slice(1)); + var data = new DecimalData(((uint)(scale << 16)) | unsignedMantissa & 0x80000000, 0, unsignedMantissa & 0x7FFFFFFF, 0); + return Unsafe.As(ref data); } - return array; - } - - public static object ReadFieldValue(ReadOnlySpan span, out int bytesRead) - { - switch ((char)span[0]) + public static IList ReadArray(ReadOnlySpan span, out int bytesRead) { - case 'S': - bytesRead = 1 + ReadLongstr(span.Slice(1), out var bytes); - return bytes; - case 't': - bytesRead = 2; - return span[1] != 0 ? TrueBoolean : FalseBoolean; - case 'I': - bytesRead = 5; - return NetworkOrderDeserializer.ReadInt32(span.Slice(1)); - case 'V': - bytesRead = 1; + bytesRead = 4; + long arrayLength = NetworkOrderDeserializer.ReadUInt32(span); + if (arrayLength == 0) + { return null; - default: - return ReadFieldValueSlow(span, out bytesRead); + } + List array = new List(); + while (bytesRead - 4 < arrayLength) + { + array.Add(ReadFieldValue(span.Slice(bytesRead), out int fieldValueBytesRead)); + bytesRead += fieldValueBytesRead; + } + + return array; } - // Moved out of outer switch to have a shorter main method (improves performance) - static object ReadFieldValueSlow(ReadOnlySpan span, out int bytesRead) + public static object ReadFieldValue(ReadOnlySpan span, out int bytesRead) { - var slice = span.Slice(1); switch ((char)span[0]) { - case 'F': - bytesRead = 1 + ReadDictionary(slice, out var dictionary); - return dictionary; - case 'A': - IList arrayResult = ReadArray(slice, out int arrayBytesRead); - bytesRead = 1 + arrayBytesRead; - return arrayResult; - case 'l': - bytesRead = 9; - return NetworkOrderDeserializer.ReadInt64(slice); - case 'i': - bytesRead = 5; - return NetworkOrderDeserializer.ReadUInt32(slice); - case 'D': - bytesRead = 6; - return ReadDecimal(slice); - case 'B': + case 'S': + bytesRead = 1 + ReadLongstr(span.Slice(1), out var bytes); + return bytes; + case 't': bytesRead = 2; - return span[1]; - case 'b': - bytesRead = 2; - return (sbyte)span[1]; - case 'd': - bytesRead = 9; - return NetworkOrderDeserializer.ReadDouble(slice); - case 'f': + return span[1] != 0 ? TrueBoolean : FalseBoolean; + case 'I': bytesRead = 5; - return NetworkOrderDeserializer.ReadSingle(slice); - case 's': - bytesRead = 3; - return NetworkOrderDeserializer.ReadInt16(slice); - case 'T': - bytesRead = 1 + ReadTimestamp(slice, out var timestamp); - return timestamp; - case 'x': - bytesRead = 1 + ReadLongstr(slice, out var binaryTableResult); - return new BinaryTableValue(binaryTableResult); + return NetworkOrderDeserializer.ReadInt32(span.Slice(1)); + case 'V': + bytesRead = 1; + return null; default: - bytesRead = 0; - return ThrowInvalidTableValue((char)span[0]); + return ReadFieldValueSlow(span, out bytesRead); } - } - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int ReadLongstr(ReadOnlySpan span, out byte[] value) - { - uint byteCount = NetworkOrderDeserializer.ReadUInt32(span); - if (byteCount > int.MaxValue) - { - value = null; - return ThrowSyntaxErrorException(byteCount); + // Moved out of outer switch to have a shorter main method (improves performance) + static object ReadFieldValueSlow(ReadOnlySpan span, out int bytesRead) + { + var slice = span.Slice(1); + switch ((char)span[0]) + { + case 'F': + bytesRead = 1 + ReadDictionary(slice, out var dictionary); + return dictionary; + case 'A': + IList arrayResult = ReadArray(slice, out int arrayBytesRead); + bytesRead = 1 + arrayBytesRead; + return arrayResult; + case 'l': + bytesRead = 9; + return NetworkOrderDeserializer.ReadInt64(slice); + case 'i': + bytesRead = 5; + return NetworkOrderDeserializer.ReadUInt32(slice); + case 'D': + bytesRead = 6; + return ReadDecimal(slice); + case 'B': + bytesRead = 2; + return span[1]; + case 'b': + bytesRead = 2; + return (sbyte)span[1]; + case 'd': + bytesRead = 9; + return NetworkOrderDeserializer.ReadDouble(slice); + case 'f': + bytesRead = 5; + return NetworkOrderDeserializer.ReadSingle(slice); + case 's': + bytesRead = 3; + return NetworkOrderDeserializer.ReadInt16(slice); + case 'T': + bytesRead = 1 + ReadTimestamp(slice, out var timestamp); + return timestamp; + case 'x': + bytesRead = 1 + ReadLongstr(slice, out var binaryTableResult); + return new BinaryTableValue(binaryTableResult); + default: + bytesRead = 0; + return ThrowInvalidTableValue((char)span[0]); + } + } } - value = span.Slice(4, (int)byteCount).ToArray(); - return 4 + value.Length; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int ReadShortstr(ReadOnlySpan span, out string value) - { - int byteCount = span[0]; - if (byteCount == 0) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int ReadLongstr(ReadOnlySpan span, out byte[] value) { - value = string.Empty; - return 1; + uint byteCount = NetworkOrderDeserializer.ReadUInt32(span); + if (byteCount > int.MaxValue) + { + value = null; + return ThrowSyntaxErrorException(byteCount); + } + + value = span.Slice(4, (int)byteCount).ToArray(); + return 4 + value.Length; } - // equals span.Length >= byteCount + 1 - if (span.Length > byteCount) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int ReadShortstr(ReadOnlySpan span, out string value) { + int byteCount = span[0]; + if (byteCount == 0) + { + value = string.Empty; + return 1; + } + + // equals span.Length >= byteCount + 1 + if (span.Length > byteCount) + { #if NETCOREAPP - value = UTF8.GetString(span.Slice(1, byteCount)); + value = UTF8.GetString(span.Slice(1, byteCount)); #else - unsafe - { - fixed (byte* bytes = span.Slice(1)) + unsafe { - value = UTF8.GetString(bytes, byteCount); + fixed (byte* bytes = span.Slice(1)) + { + value = UTF8.GetString(bytes, byteCount); + } } - } #endif - return 1 + byteCount; - } - - value = string.Empty; - return ThrowArgumentOutOfRangeException(span.Length, byteCount + 1); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int ReadBits(ReadOnlySpan span, out bool val) - { - val = (span[0] & 0b0000_0001) != 0; - return 1; - } + return 1 + byteCount; + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int ReadBits(ReadOnlySpan span, out bool val1, out bool val2) - { - byte bits = span[0]; - val1 = (bits & 0b0000_0001) != 0; - val2 = (bits & 0b0000_0010) != 0; - return 1; - } + value = string.Empty; + return ThrowArgumentOutOfRangeException(span.Length, byteCount + 1); + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int ReadBits(ReadOnlySpan span, out bool val1, out bool val2, out bool val3) - { - byte bits = span[0]; - val1 = (bits & 0b0000_0001) != 0; - val2 = (bits & 0b0000_0010) != 0; - val3 = (bits & 0b0000_0100) != 0; - return 1; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int ReadBits(ReadOnlySpan span, out bool val) + { + val = (span[0] & 0b0000_0001) != 0; + return 1; + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int ReadBits(ReadOnlySpan span, out bool val1, out bool val2, out bool val3, out bool val4) - { - byte bits = span[0]; - val1 = (bits & 0b0000_0001) != 0; - val2 = (bits & 0b0000_0010) != 0; - val3 = (bits & 0b0000_0100) != 0; - val4 = (bits & 0b0000_1000) != 0; - return 1; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int ReadBits(ReadOnlySpan span, out bool val1, out bool val2) + { + byte bits = span[0]; + val1 = (bits & 0b0000_0001) != 0; + val2 = (bits & 0b0000_0010) != 0; + return 1; + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int ReadBits(ReadOnlySpan span, out bool val1, out bool val2, out bool val3, out bool val4, out bool val5) - { - byte bits = span[0]; - val1 = (bits & 0b0000_0001) != 0; - val2 = (bits & 0b0000_0010) != 0; - val3 = (bits & 0b0000_0100) != 0; - val4 = (bits & 0b0000_1000) != 0; - val5 = (bits & 0b0001_0000) != 0; - return 1; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int ReadBits(ReadOnlySpan span, out bool val1, out bool val2, out bool val3) + { + byte bits = span[0]; + val1 = (bits & 0b0000_0001) != 0; + val2 = (bits & 0b0000_0010) != 0; + val3 = (bits & 0b0000_0100) != 0; + return 1; + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int ReadShort(ReadOnlySpan span, out ushort value) - { - value = NetworkOrderDeserializer.ReadUInt16(span); - return 2; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int ReadBits(ReadOnlySpan span, out bool val1, out bool val2, out bool val3, out bool val4) + { + byte bits = span[0]; + val1 = (bits & 0b0000_0001) != 0; + val2 = (bits & 0b0000_0010) != 0; + val3 = (bits & 0b0000_0100) != 0; + val4 = (bits & 0b0000_1000) != 0; + return 1; + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int ReadLong(ReadOnlySpan span, out uint value) - { - value = NetworkOrderDeserializer.ReadUInt32(span); - return 4; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int ReadBits(ReadOnlySpan span, out bool val1, out bool val2, out bool val3, out bool val4, out bool val5) + { + byte bits = span[0]; + val1 = (bits & 0b0000_0001) != 0; + val2 = (bits & 0b0000_0010) != 0; + val3 = (bits & 0b0000_0100) != 0; + val4 = (bits & 0b0000_1000) != 0; + val5 = (bits & 0b0001_0000) != 0; + return 1; + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int ReadLonglong(ReadOnlySpan span, out ulong value) - { - value = NetworkOrderDeserializer.ReadUInt64(span); - return 8; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int ReadShort(ReadOnlySpan span, out ushort value) + { + value = NetworkOrderDeserializer.ReadUInt16(span); + return 2; + } - ///Reads an AMQP "table" definition from the reader. - /// - /// Supports the AMQP 0-8/0-9 standard entry types S, I, D, T - /// and F, as well as the QPid-0-8 specific b, d, f, l, s, t, - /// x and V types and the AMQP 0-9-1 A type. - /// - /// A . - public static int ReadDictionary(ReadOnlySpan span, out Dictionary valueDictionary) - { - long tableLength = NetworkOrderDeserializer.ReadUInt32(span); - if (tableLength == 0) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int ReadLong(ReadOnlySpan span, out uint value) { - valueDictionary = null; + value = NetworkOrderDeserializer.ReadUInt32(span); return 4; } - span = span.Slice(4); - valueDictionary = new Dictionary(); - int bytesRead = 0; - while (bytesRead < tableLength) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int ReadLonglong(ReadOnlySpan span, out ulong value) { - bytesRead += ReadShortstr(span.Slice(bytesRead), out string key); - valueDictionary[key] = ReadFieldValue(span.Slice(bytesRead), out int valueBytesRead); - bytesRead += valueBytesRead; + value = NetworkOrderDeserializer.ReadUInt64(span); + return 8; } - return 4 + bytesRead; - } + ///Reads an AMQP "table" definition from the reader. + /// + /// Supports the AMQP 0-8/0-9 standard entry types S, I, D, T + /// and F, as well as the QPid-0-8 specific b, d, f, l, s, t, + /// x and V types and the AMQP 0-9-1 A type. + /// + /// A . + public static int ReadDictionary(ReadOnlySpan span, out Dictionary valueDictionary) + { + long tableLength = NetworkOrderDeserializer.ReadUInt32(span); + if (tableLength == 0) + { + valueDictionary = null; + return 4; + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int ReadTimestamp(ReadOnlySpan span, out AmqpTimestamp value) - { - // 0-9 is afaict silent on the signedness of the timestamp. - // See also MethodArgumentWriter.WriteTimestamp and AmqpTimestamp itself - value = new AmqpTimestamp((long)NetworkOrderDeserializer.ReadUInt64(span)); - return 8; - } + span = span.Slice(4); + valueDictionary = new Dictionary(); + int bytesRead = 0; + while (bytesRead < tableLength) + { + bytesRead += ReadShortstr(span.Slice(bytesRead), out string key); + valueDictionary[key] = ReadFieldValue(span.Slice(bytesRead), out int valueBytesRead); + bytesRead += valueBytesRead; + } - public static int ThrowSyntaxErrorException(uint byteCount) - => throw new SyntaxErrorException($"Long string too long; byte length={byteCount}, max={int.MaxValue}"); + return 4 + bytesRead; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int ReadTimestamp(ReadOnlySpan span, out AmqpTimestamp value) + { + // 0-9 is afaict silent on the signedness of the timestamp. + // See also MethodArgumentWriter.WriteTimestamp and AmqpTimestamp itself + value = new AmqpTimestamp((long)NetworkOrderDeserializer.ReadUInt64(span)); + return 8; + } + + public static int ThrowSyntaxErrorException(uint byteCount) + => throw new SyntaxErrorException($"Long string too long; byte length={byteCount}, max={int.MaxValue}"); - private static int ThrowInvalidTableValue(char type) - => throw new SyntaxErrorException($"Unrecognised type in table: {type}"); + private static int ThrowInvalidTableValue(char type) + => throw new SyntaxErrorException($"Unrecognised type in table: {type}"); - private static void ThrowInvalidDecimalScale(int scale) - => throw new SyntaxErrorException($"Unrepresentable AMQP decimal table field: scale={scale}"); + private static void ThrowInvalidDecimalScale(int scale) + => throw new SyntaxErrorException($"Unrepresentable AMQP decimal table field: scale={scale}"); + } } diff --git a/projects/RabbitMQ.Client/client/impl/WireFormatting.Write.cs b/projects/RabbitMQ.Client/client/impl/WireFormatting.Write.cs index 7a9bcbc2f7..710564b421 100644 --- a/projects/RabbitMQ.Client/client/impl/WireFormatting.Write.cs +++ b/projects/RabbitMQ.Client/client/impl/WireFormatting.Write.cs @@ -37,455 +37,456 @@ using RabbitMQ.Client.Exceptions; using RabbitMQ.Util; -namespace RabbitMQ.Client.Impl; - -internal static partial class WireFormatting +namespace RabbitMQ.Client.Impl { - public static int WriteArray(ref byte destination, IList val) + internal static partial class WireFormatting { - if (val is null || val.Count == 0) - { - NetworkOrderSerializer.WriteUInt32(ref destination, 0); - return 4; - } - - int bytesWritten = 4; - for (int index = 0; index < val.Count; index++) + public static int WriteArray(ref byte destination, IList val) { - bytesWritten += WriteFieldValue(ref destination.GetOffset(bytesWritten), val[index]); - } + if (val is null || val.Count == 0) + { + NetworkOrderSerializer.WriteUInt32(ref destination, 0); + return 4; + } - NetworkOrderSerializer.WriteUInt32(ref destination, (uint)bytesWritten - 4u); - return bytesWritten; - } + int bytesWritten = 4; + for (int index = 0; index < val.Count; index++) + { + bytesWritten += WriteFieldValue(ref destination.GetOffset(bytesWritten), val[index]); + } - public static int GetArrayByteCount(IList val) - { - if (val is null || val.Count == 0) - { - return 4; + NetworkOrderSerializer.WriteUInt32(ref destination, (uint)bytesWritten - 4u); + return bytesWritten; } - int byteCount = 4; - if (val is List valList) + public static int GetArrayByteCount(IList val) { - for (int index = 0; index < valList.Count; index++) + if (val is null || val.Count == 0) { - byteCount += GetFieldValueByteCount(valList[index]); + return 4; } - } - else - { - for (int index = 0; index < val.Count; index++) + + int byteCount = 4; + if (val is List valList) { - byteCount += GetFieldValueByteCount(val[index]); + for (int index = 0; index < valList.Count; index++) + { + byteCount += GetFieldValueByteCount(valList[index]); + } + } + else + { + for (int index = 0; index < val.Count; index++) + { + byteCount += GetFieldValueByteCount(val[index]); + } } - } - return byteCount; - } + return byteCount; + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] #if NETCOREAPP - public static int GetByteCount(ReadOnlySpan val) => val.IsEmpty ? 0 : UTF8.GetByteCount(val); + public static int GetByteCount(ReadOnlySpan val) => val.IsEmpty ? 0 : UTF8.GetByteCount(val); #else - public static int GetByteCount(string val) => string.IsNullOrEmpty(val) ? 0 : UTF8.GetByteCount(val); + public static int GetByteCount(string val) => string.IsNullOrEmpty(val) ? 0 : UTF8.GetByteCount(val); #endif - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int WriteDecimal(ref byte destination, decimal value) - { - // Cast the decimal to our struct to avoid the decimal.GetBits allocations. - DecimalData data = Unsafe.As(ref value); - // According to the documentation :- - // - word 0: low-order "mantissa" - // - word 1, word 2: medium- and high-order "mantissa" - // - word 3: mostly reserved; "exponent" and sign bit - // In one way, this is broader than AMQP: the mantissa is larger. - // In another way, smaller: the exponent ranges 0-28 inclusive. - // We need to be careful about the range of word 0, too: we can - // only take 31 bits worth of it, since the sign bit needs to - // fit in there too. - if (data.Mid != 0 || // mantissa extends into middle word - data.Hi != 0 || // mantissa extends into top word - data.Lo < 0) // mantissa extends beyond 31 bits + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int WriteDecimal(ref byte destination, decimal value) { - return ThrowWireFormattingException(value); - } - - destination = (byte)((data.Flags >> 16) & 0xFF); - WriteLong(ref destination.GetOffset(1), (data.Flags & 0b1000_0000_0000_0000_0000_0000_0000_0000) | (data.Lo & 0b0111_1111_1111_1111_1111_1111_1111_1111)); - return 5; - } + // Cast the decimal to our struct to avoid the decimal.GetBits allocations. + DecimalData data = Unsafe.As(ref value); + // According to the documentation :- + // - word 0: low-order "mantissa" + // - word 1, word 2: medium- and high-order "mantissa" + // - word 3: mostly reserved; "exponent" and sign bit + // In one way, this is broader than AMQP: the mantissa is larger. + // In another way, smaller: the exponent ranges 0-28 inclusive. + // We need to be careful about the range of word 0, too: we can + // only take 31 bits worth of it, since the sign bit needs to + // fit in there too. + if (data.Mid != 0 || // mantissa extends into middle word + data.Hi != 0 || // mantissa extends into top word + data.Lo < 0) // mantissa extends beyond 31 bits + { + return ThrowWireFormattingException(value); + } - public static int WriteFieldValue(ref byte destination, object value) - { - if (value == null) - { - destination = (byte)'V'; - return 1; + destination = (byte)((data.Flags >> 16) & 0xFF); + WriteLong(ref destination.GetOffset(1), (data.Flags & 0b1000_0000_0000_0000_0000_0000_0000_0000) | (data.Lo & 0b0111_1111_1111_1111_1111_1111_1111_1111)); + return 5; } - // Order by likelihood of occurrence - ref byte fieldValue = ref destination.GetOffset(1); - switch (value) + public static int WriteFieldValue(ref byte destination, object value) { - case string val: - destination = (byte)'S'; - return 1 + WriteLongstr(ref fieldValue, val); - case bool val: - destination = (byte)'t'; - fieldValue = val.ToByte(); - return 2; - case int val: - destination = (byte)'I'; - NetworkOrderSerializer.WriteInt32(ref fieldValue, val); - return 5; - case byte[] val: - destination = (byte)'S'; - return 1 + WriteLongstr(ref fieldValue, val); - default: - return WriteFieldValueSlow(ref destination, ref fieldValue, value); + if (value == null) + { + destination = (byte)'V'; + return 1; + } + + // Order by likelihood of occurrence + ref byte fieldValue = ref destination.GetOffset(1); + switch (value) + { + case string val: + destination = (byte)'S'; + return 1 + WriteLongstr(ref fieldValue, val); + case bool val: + destination = (byte)'t'; + fieldValue = val.ToByte(); + return 2; + case int val: + destination = (byte)'I'; + NetworkOrderSerializer.WriteInt32(ref fieldValue, val); + return 5; + case byte[] val: + destination = (byte)'S'; + return 1 + WriteLongstr(ref fieldValue, val); + default: + return WriteFieldValueSlow(ref destination, ref fieldValue, value); + } + + // Moved out of outer switch to have a shorter main method (improves performance) + static int WriteFieldValueSlow(ref byte destination, ref byte fieldValue, object value) + { + // Order by likelihood of occurrence + switch (value) + { + case float val: + destination = (byte)'f'; + NetworkOrderSerializer.WriteSingle(ref fieldValue, val); + return 5; + case IDictionary val: + destination = (byte)'F'; + return 1 + WriteTable(ref fieldValue, val); + case IList val: + destination = (byte)'A'; + return 1 + WriteArray(ref fieldValue, val); + case AmqpTimestamp val: + destination = (byte)'T'; + return 1 + WriteTimestamp(ref fieldValue, val); + case double val: + destination = (byte)'d'; + NetworkOrderSerializer.WriteDouble(ref fieldValue, val); + return 9; + case long val: + destination = (byte)'l'; + NetworkOrderSerializer.WriteInt64(ref fieldValue, val); + return 9; + case byte val: + destination = (byte)'B'; + fieldValue = val; + return 2; + case sbyte val: + destination = (byte)'b'; + fieldValue = (byte)val; + return 2; + case short val: + destination = (byte)'s'; + NetworkOrderSerializer.WriteInt16(ref fieldValue, val); + return 3; + case uint val: + destination = (byte)'i'; + NetworkOrderSerializer.WriteUInt32(ref fieldValue, val); + return 5; + case decimal val: + destination = (byte)'D'; + return 1 + WriteDecimal(ref fieldValue, val); + case IDictionary val: + destination = (byte)'F'; + return 1 + WriteTable(ref fieldValue, val); + case BinaryTableValue val: + destination = (byte)'x'; + return 1 + WriteLongstr(ref fieldValue, val.Bytes); + default: + return ThrowInvalidTableValue(value); + } + } } - // Moved out of outer switch to have a shorter main method (improves performance) - static int WriteFieldValueSlow(ref byte destination, ref byte fieldValue, object value) + public static int GetFieldValueByteCount(object value) { // Order by likelihood of occurrence switch (value) { - case float val: - destination = (byte)'f'; - NetworkOrderSerializer.WriteSingle(ref fieldValue, val); + case null: + return 1; + case string val: + return 5 + GetByteCount(val); + case bool _: + return 2; + case int _: + case float _: return 5; + case byte[] val: + return 5 + val.Length; case IDictionary val: - destination = (byte)'F'; - return 1 + WriteTable(ref fieldValue, val); + return 1 + GetTableByteCount(val); case IList val: - destination = (byte)'A'; - return 1 + WriteArray(ref fieldValue, val); - case AmqpTimestamp val: - destination = (byte)'T'; - return 1 + WriteTimestamp(ref fieldValue, val); - case double val: - destination = (byte)'d'; - NetworkOrderSerializer.WriteDouble(ref fieldValue, val); - return 9; - case long val: - destination = (byte)'l'; - NetworkOrderSerializer.WriteInt64(ref fieldValue, val); + return 1 + GetArrayByteCount(val); + case AmqpTimestamp _: + case double _: + case long _: return 9; - case byte val: - destination = (byte)'B'; - fieldValue = val; + case byte _: + case sbyte _: return 2; - case sbyte val: - destination = (byte)'b'; - fieldValue = (byte)val; - return 2; - case short val: - destination = (byte)'s'; - NetworkOrderSerializer.WriteInt16(ref fieldValue, val); + case short _: return 3; - case uint val: - destination = (byte)'i'; - NetworkOrderSerializer.WriteUInt32(ref fieldValue, val); + case uint _: return 5; - case decimal val: - destination = (byte)'D'; - return 1 + WriteDecimal(ref fieldValue, val); + case decimal _: + return 6; case IDictionary val: - destination = (byte)'F'; - return 1 + WriteTable(ref fieldValue, val); + return 1 + GetTableByteCount(val); case BinaryTableValue val: - destination = (byte)'x'; - return 1 + WriteLongstr(ref fieldValue, val.Bytes); + return 5 + val.Bytes.Length; default: return ThrowInvalidTableValue(value); } } - } - public static int GetFieldValueByteCount(object value) - { - // Order by likelihood of occurrence - switch (value) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int WriteLong(ref byte destination, uint val) { - case null: - return 1; - case string val: - return 5 + GetByteCount(val); - case bool _: - return 2; - case int _: - case float _: - return 5; - case byte[] val: - return 5 + val.Length; - case IDictionary val: - return 1 + GetTableByteCount(val); - case IList val: - return 1 + GetArrayByteCount(val); - case AmqpTimestamp _: - case double _: - case long _: - return 9; - case byte _: - case sbyte _: - return 2; - case short _: - return 3; - case uint _: - return 5; - case decimal _: - return 6; - case IDictionary val: - return 1 + GetTableByteCount(val); - case BinaryTableValue val: - return 5 + val.Bytes.Length; - default: - return ThrowInvalidTableValue(value); + NetworkOrderSerializer.WriteUInt32(ref destination, val); + return 4; } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int WriteLong(ref byte destination, uint val) - { - NetworkOrderSerializer.WriteUInt32(ref destination, val); - return 4; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int WriteLonglong(ref byte destination, ulong val) - { - NetworkOrderSerializer.WriteUInt64(ref destination, val); - return 8; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int WriteBits(ref byte destination, bool val) - { - destination = val.ToByte(); - return 1; - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int WriteBits(ref byte destination, bool val1, bool val2) - { - int a = val1.ToByte() + val2.ToByte() * 2; - destination = (byte)a; - return 1; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int WriteLonglong(ref byte destination, ulong val) + { + NetworkOrderSerializer.WriteUInt64(ref destination, val); + return 8; + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int WriteBits(ref byte destination, bool val1, bool val2, bool val3) - { - int a = val1.ToByte() + val2.ToByte() * 2 + val3.ToByte() * 4; - destination = (byte)a; - return 1; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int WriteBits(ref byte destination, bool val) + { + destination = val.ToByte(); + return 1; + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int WriteBits(ref byte destination, bool val1, bool val2, bool val3, bool val4) - { - int a = val1.ToByte() + val2.ToByte() * 2 + val3.ToByte() * 4 + val4.ToByte() * 8; - destination = (byte)a; - return 1; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int WriteBits(ref byte destination, bool val1, bool val2) + { + int a = val1.ToByte() + val2.ToByte() * 2; + destination = (byte)a; + return 1; + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int WriteBits(ref byte destination, bool val1, bool val2, bool val3, bool val4, bool val5) - { - int a = val1.ToByte() + val2.ToByte() * 2 + val3.ToByte() * 4 + val4.ToByte() * 8; - int b = val5.ToByte(); - destination = (byte)(a | (b << 4)); - return 1; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int WriteBits(ref byte destination, bool val1, bool val2, bool val3) + { + int a = val1.ToByte() + val2.ToByte() * 2 + val3.ToByte() * 4; + destination = (byte)a; + return 1; + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int WriteLongstr(ref byte destination, ReadOnlySpan val) - { - WriteLong(ref destination, (uint)val.Length); - Unsafe.CopyBlockUnaligned(ref destination.GetOffset(4), ref val.GetStart(), (uint)val.Length); - return 4 + val.Length; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int WriteBits(ref byte destination, bool val1, bool val2, bool val3, bool val4) + { + int a = val1.ToByte() + val2.ToByte() * 2 + val3.ToByte() * 4 + val4.ToByte() * 8; + destination = (byte)a; + return 1; + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int WriteShort(ref byte destination, ushort val) - { - NetworkOrderSerializer.WriteUInt16(ref destination, val); - return 2; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int WriteBits(ref byte destination, bool val1, bool val2, bool val3, bool val4, bool val5) + { + int a = val1.ToByte() + val2.ToByte() * 2 + val3.ToByte() * 4 + val4.ToByte() * 8; + int b = val5.ToByte(); + destination = (byte)(a | (b << 4)); + return 1; + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int WriteShortstr(ref byte destination, ReadOnlySpan value) - { - var length = value.Length; - if (length <= byte.MaxValue) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int WriteLongstr(ref byte destination, ReadOnlySpan val) { - destination = (byte)length; - Unsafe.CopyBlockUnaligned(ref destination.GetOffset(1), ref value.GetStart(), (uint)value.Length); - return length + 1; + WriteLong(ref destination, (uint)val.Length); + Unsafe.CopyBlockUnaligned(ref destination.GetOffset(4), ref val.GetStart(), (uint)val.Length); + return 4 + val.Length; } - return ThrowArgumentTooLong(length); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int WriteShort(ref byte destination, ushort val) + { + NetworkOrderSerializer.WriteUInt16(ref destination, val); + return 2; + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int WriteShortstr(ref byte destination, string val) - { - int bytesWritten = 0; - if (!string.IsNullOrEmpty(val)) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int WriteShortstr(ref byte destination, ReadOnlySpan value) { - unsafe + var length = value.Length; + if (length <= byte.MaxValue) { - - ref byte valDestination = ref destination.GetOffset(1); - fixed (char* chars = val) - fixed (byte* bytes = &valDestination) - { - bytesWritten = UTF8.GetBytes(chars, val.Length, bytes, byte.MaxValue); - } + destination = (byte)length; + Unsafe.CopyBlockUnaligned(ref destination.GetOffset(1), ref value.GetStart(), (uint)value.Length); + return length + 1; } - } - destination = unchecked((byte)bytesWritten); - return bytesWritten + 1; - } + return ThrowArgumentTooLong(length); + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int WriteLongstr(ref byte destination, string val) - { - static int GetBytes(ref byte destination, string val) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int WriteShortstr(ref byte destination, string val) { - unsafe + int bytesWritten = 0; + if (!string.IsNullOrEmpty(val)) { - fixed (char* chars = val) - fixed (byte* bytes = &destination) + unsafe { - return UTF8.GetBytes(chars, val.Length, bytes, int.MaxValue); + + ref byte valDestination = ref destination.GetOffset(1); + fixed (char* chars = val) + fixed (byte* bytes = &valDestination) + { + bytesWritten = UTF8.GetBytes(chars, val.Length, bytes, byte.MaxValue); + } } } - } - int bytesWritten = string.IsNullOrEmpty(val) ? 0 : GetBytes(ref destination.GetOffset(4), val); - NetworkOrderSerializer.WriteUInt32(ref destination, (uint)bytesWritten); - return bytesWritten + 4; - } - - public static int WriteTable(ref byte destination, IDictionary val) - { - if (val is null || val.Count == 0) - { - NetworkOrderSerializer.WriteUInt32(ref destination, 0u); - return 4; + destination = unchecked((byte)bytesWritten); + return bytesWritten + 1; } - // Let's only write after the length header. - int bytesWritten = 4; - foreach (DictionaryEntry entry in val) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int WriteLongstr(ref byte destination, string val) { - bytesWritten += WriteShortstr(ref destination.GetOffset(bytesWritten), entry.Key.ToString()); - bytesWritten += WriteFieldValue(ref destination.GetOffset(bytesWritten), entry.Value); - } - - NetworkOrderSerializer.WriteUInt32(ref destination, (uint)(bytesWritten - 4)); - return bytesWritten; - } + static int GetBytes(ref byte destination, string val) + { + unsafe + { + fixed (char* chars = val) + fixed (byte* bytes = &destination) + { + return UTF8.GetBytes(chars, val.Length, bytes, int.MaxValue); + } + } + } - public static int WriteTable(ref byte destination, IDictionary val) - { - if (val is null || val.Count == 0) - { - NetworkOrderSerializer.WriteUInt32(ref destination, 0); - return 4; + int bytesWritten = string.IsNullOrEmpty(val) ? 0 : GetBytes(ref destination.GetOffset(4), val); + NetworkOrderSerializer.WriteUInt32(ref destination, (uint)bytesWritten); + return bytesWritten + 4; } - // Let's only write after the length header. - int bytesWritten = 4; - if (val is Dictionary dict) + public static int WriteTable(ref byte destination, IDictionary val) { - foreach (KeyValuePair entry in dict) + if (val is null || val.Count == 0) { - bytesWritten += WriteShortstr(ref destination.GetOffset(bytesWritten), entry.Key); - bytesWritten += WriteFieldValue(ref destination.GetOffset(bytesWritten), entry.Value); + NetworkOrderSerializer.WriteUInt32(ref destination, 0u); + return 4; } - } - else - { - foreach (KeyValuePair entry in val) + + // Let's only write after the length header. + int bytesWritten = 4; + foreach (DictionaryEntry entry in val) { - bytesWritten += WriteShortstr(ref destination.GetOffset(bytesWritten), entry.Key); + bytesWritten += WriteShortstr(ref destination.GetOffset(bytesWritten), entry.Key.ToString()); bytesWritten += WriteFieldValue(ref destination.GetOffset(bytesWritten), entry.Value); } - } - - NetworkOrderSerializer.WriteUInt32(ref destination, (uint)(bytesWritten - 4)); - return bytesWritten; - } - public static int GetTableByteCount(IDictionary val) - { - if (val is null || val.Count == 0) - { - return 4; + NetworkOrderSerializer.WriteUInt32(ref destination, (uint)(bytesWritten - 4)); + return bytesWritten; } - int byteCount = 4; - foreach (DictionaryEntry entry in val) + public static int WriteTable(ref byte destination, IDictionary val) { - byteCount += GetByteCount(entry.Key.ToString()) + 1; - byteCount += GetFieldValueByteCount(entry.Value); - } + if (val is null || val.Count == 0) + { + NetworkOrderSerializer.WriteUInt32(ref destination, 0); + return 4; + } - return byteCount; - } + // Let's only write after the length header. + int bytesWritten = 4; + if (val is Dictionary dict) + { + foreach (KeyValuePair entry in dict) + { + bytesWritten += WriteShortstr(ref destination.GetOffset(bytesWritten), entry.Key); + bytesWritten += WriteFieldValue(ref destination.GetOffset(bytesWritten), entry.Value); + } + } + else + { + foreach (KeyValuePair entry in val) + { + bytesWritten += WriteShortstr(ref destination.GetOffset(bytesWritten), entry.Key); + bytesWritten += WriteFieldValue(ref destination.GetOffset(bytesWritten), entry.Value); + } + } - public static int GetTableByteCount(IDictionary val) - { - if (val is null || val.Count == 0) - { - return 4; + NetworkOrderSerializer.WriteUInt32(ref destination, (uint)(bytesWritten - 4)); + return bytesWritten; } - int byteCount = 4; - if (val is Dictionary dict) + public static int GetTableByteCount(IDictionary val) { - foreach (KeyValuePair entry in dict) + if (val is null || val.Count == 0) + { + return 4; + } + + int byteCount = 4; + foreach (DictionaryEntry entry in val) { - byteCount += GetByteCount(entry.Key) + 1; + byteCount += GetByteCount(entry.Key.ToString()) + 1; byteCount += GetFieldValueByteCount(entry.Value); } + + return byteCount; } - else + + public static int GetTableByteCount(IDictionary val) { - foreach (KeyValuePair entry in val) + if (val is null || val.Count == 0) { - byteCount += GetByteCount(entry.Key) + 1; - byteCount += GetFieldValueByteCount(entry.Value); + return 4; } - } - return byteCount; - } + int byteCount = 4; + if (val is Dictionary dict) + { + foreach (KeyValuePair entry in dict) + { + byteCount += GetByteCount(entry.Key) + 1; + byteCount += GetFieldValueByteCount(entry.Value); + } + } + else + { + foreach (KeyValuePair entry in val) + { + byteCount += GetByteCount(entry.Key) + 1; + byteCount += GetFieldValueByteCount(entry.Value); + } + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int WriteTimestamp(ref byte destination, AmqpTimestamp val) - { - // 0-9 is afaict silent on the signedness of the timestamp. - // See also MethodArgumentReader.ReadTimestamp and AmqpTimestamp itself - return WriteLonglong(ref destination, (ulong)val.UnixTime); - } + return byteCount; + } - public static int ThrowArgumentTooLong(int length) - => throw new ArgumentOutOfRangeException("value", $"Value exceeds the maximum allowed length of 255 bytes, was {length} long."); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int WriteTimestamp(ref byte destination, AmqpTimestamp val) + { + // 0-9 is afaict silent on the signedness of the timestamp. + // See also MethodArgumentReader.ReadTimestamp and AmqpTimestamp itself + return WriteLonglong(ref destination, (ulong)val.UnixTime); + } - public static int ThrowArgumentOutOfRangeException(int orig, int expected) - => throw new ArgumentOutOfRangeException("span", $"Span has not enough space ({orig} instead of {expected})"); + public static int ThrowArgumentTooLong(int length) + => throw new ArgumentOutOfRangeException("value", $"Value exceeds the maximum allowed length of 255 bytes, was {length} long."); - private static int ThrowWireFormattingException(decimal value) - => throw new WireFormattingException("Decimal overflow in AMQP encoding", value); + public static int ThrowArgumentOutOfRangeException(int orig, int expected) + => throw new ArgumentOutOfRangeException("span", $"Span has not enough space ({orig} instead of {expected})"); - private static int ThrowInvalidTableValue(object value) - => throw new WireFormattingException($"Value of type '{value.GetType().Name}' cannot appear as table value", value); + private static int ThrowWireFormattingException(decimal value) + => throw new WireFormattingException("Decimal overflow in AMQP encoding", value); + + private static int ThrowInvalidTableValue(object value) + => throw new WireFormattingException($"Value of type '{value.GetType().Name}' cannot appear as table value", value); + } } diff --git a/projects/RabbitMQ.Client/client/impl/WireFormatting.cs b/projects/RabbitMQ.Client/client/impl/WireFormatting.cs index 9a6f6d06ff..0d48a07791 100644 --- a/projects/RabbitMQ.Client/client/impl/WireFormatting.cs +++ b/projects/RabbitMQ.Client/client/impl/WireFormatting.cs @@ -31,38 +31,39 @@ using System.Text; -namespace RabbitMQ.Client.Impl; - -internal static partial class WireFormatting +namespace RabbitMQ.Client.Impl { - public static readonly object TrueBoolean = true; - public static readonly object FalseBoolean = false; - - // * DESCRIPTION TAKEN FROM MS REFERENCE SOURCE * - // https://github.com/microsoft/referencesource/blob/master/mscorlib/system/decimal.cs - // The lo, mid, hi, and flags fields contain the representation of the - // Decimal value. The lo, mid, and hi fields contain the 96-bit integer - // part of the Decimal. Bits 0-15 (the lower word) of the flags field are - // unused and must be zero; bits 16-23 contain must contain a value between - // 0 and 28, indicating the power of 10 to divide the 96-bit integer part - // by to produce the Decimal value; bits 24-30 are unused and must be zero; - // and finally bit 31 indicates the sign of the Decimal value, 0 meaning - // positive and 1 meaning negative. - readonly struct DecimalData + internal static partial class WireFormatting { - public readonly uint Flags; - public readonly uint Hi; - public readonly uint Lo; - public readonly uint Mid; + public static readonly object TrueBoolean = true; + public static readonly object FalseBoolean = false; - internal DecimalData(uint flags, uint hi, uint lo, uint mid) + // * DESCRIPTION TAKEN FROM MS REFERENCE SOURCE * + // https://github.com/microsoft/referencesource/blob/master/mscorlib/system/decimal.cs + // The lo, mid, hi, and flags fields contain the representation of the + // Decimal value. The lo, mid, and hi fields contain the 96-bit integer + // part of the Decimal. Bits 0-15 (the lower word) of the flags field are + // unused and must be zero; bits 16-23 contain must contain a value between + // 0 and 28, indicating the power of 10 to divide the 96-bit integer part + // by to produce the Decimal value; bits 24-30 are unused and must be zero; + // and finally bit 31 indicates the sign of the Decimal value, 0 meaning + // positive and 1 meaning negative. + readonly struct DecimalData { - Flags = flags; - Hi = hi; - Lo = lo; - Mid = mid; + public readonly uint Flags; + public readonly uint Hi; + public readonly uint Lo; + public readonly uint Mid; + + internal DecimalData(uint flags, uint hi, uint lo, uint mid) + { + Flags = flags; + Hi = hi; + Lo = lo; + Mid = mid; + } } - } - private static readonly UTF8Encoding UTF8 = new UTF8Encoding(); + private static readonly UTF8Encoding UTF8 = new UTF8Encoding(); + } } diff --git a/projects/RabbitMQ.Client/client/logging/ESLog.cs b/projects/RabbitMQ.Client/client/logging/ESLog.cs index bf10e9f5bd..dca4c15f4a 100644 --- a/projects/RabbitMQ.Client/client/logging/ESLog.cs +++ b/projects/RabbitMQ.Client/client/logging/ESLog.cs @@ -29,40 +29,41 @@ // Copyright (c) 2007-2020 VMware, Inc. All rights reserved. //--------------------------------------------------------------------------- -namespace RabbitMQ.Client.Logging; - -internal static class ESLog +namespace RabbitMQ.Client.Logging { - public static void Info(string message) + internal static class ESLog { - Logging.RabbitMqClientEventSource.Log.Info(message); - } + public static void Info(string message) + { + Logging.RabbitMqClientEventSource.Log.Info(message); + } - public static void Info(string message, params object[] args) - { - string msg = string.Format(message, args); - Info(msg); - } + public static void Info(string message, params object[] args) + { + string msg = string.Format(message, args); + Info(msg); + } - public static void Warn(string message) - { - Logging.RabbitMqClientEventSource.Log.Warn(message); - } + public static void Warn(string message) + { + Logging.RabbitMqClientEventSource.Log.Warn(message); + } - public static void Warn(string message, params object[] args) - { - string msg = string.Format(message, args); - Warn(msg); - } + public static void Warn(string message, params object[] args) + { + string msg = string.Format(message, args); + Warn(msg); + } - public static void Error(string message, System.Exception ex) - { - Logging.RabbitMqClientEventSource.Log.Error(message, ex); - } + public static void Error(string message, System.Exception ex) + { + Logging.RabbitMqClientEventSource.Log.Error(message, ex); + } - public static void Error(string message, System.Exception ex, params object[] args) - { - string msg = string.Format(message, args); - Error(msg, ex); + public static void Error(string message, System.Exception ex, params object[] args) + { + string msg = string.Format(message, args); + Error(msg, ex); + } } } diff --git a/projects/RabbitMQ.Client/client/logging/RabbitMqClientEventSource.Counters.cs b/projects/RabbitMQ.Client/client/logging/RabbitMqClientEventSource.Counters.cs index 17396d11e9..4cbee694d9 100644 --- a/projects/RabbitMQ.Client/client/logging/RabbitMqClientEventSource.Counters.cs +++ b/projects/RabbitMQ.Client/client/logging/RabbitMqClientEventSource.Counters.cs @@ -33,88 +33,89 @@ using System.Diagnostics.Tracing; using System.Threading; -namespace RabbitMQ.Client.Logging; - -#nullable enable -internal sealed partial class RabbitMqClientEventSource +namespace RabbitMQ.Client.Logging { - private static int ConnectionsOpened; - private static int ConnectionsClosed; - private static int ChannelsOpened; - private static int ChannelsClosed; - private static long BytesSent; - private static long BytesReceived; - private static long CommandsSent; - private static long CommandsReceived; +#nullable enable + internal sealed partial class RabbitMqClientEventSource + { + private static int ConnectionsOpened; + private static int ConnectionsClosed; + private static int ChannelsOpened; + private static int ChannelsClosed; + private static long BytesSent; + private static long BytesReceived; + private static long CommandsSent; + private static long CommandsReceived; #if !NETSTANDARD - private PollingCounter? _connectionOpenedCounter; - private PollingCounter? _openConnectionCounter; - private PollingCounter? _channelOpenedCounter; - private PollingCounter? _openChannelCounter; - private IncrementingPollingCounter? _bytesSentCounter; - private IncrementingPollingCounter? _bytesReceivedCounter; - private IncrementingPollingCounter? _commandSentCounter; - private IncrementingPollingCounter? _commandReceivedCounter; + private PollingCounter? _connectionOpenedCounter; + private PollingCounter? _openConnectionCounter; + private PollingCounter? _channelOpenedCounter; + private PollingCounter? _openChannelCounter; + private IncrementingPollingCounter? _bytesSentCounter; + private IncrementingPollingCounter? _bytesReceivedCounter; + private IncrementingPollingCounter? _commandSentCounter; + private IncrementingPollingCounter? _commandReceivedCounter; - protected override void OnEventCommand(EventCommandEventArgs command) - { - if (command.Command == EventCommand.Enable) + protected override void OnEventCommand(EventCommandEventArgs command) { - _connectionOpenedCounter ??= new PollingCounter("total-connections-opened", this, () => ConnectionsOpened) { DisplayName = "Total connections opened" }; - _openConnectionCounter ??= new PollingCounter("current-open-connections", this, () => ConnectionsOpened - ConnectionsClosed) { DisplayName = "Current open connections count" }; + if (command.Command == EventCommand.Enable) + { + _connectionOpenedCounter ??= new PollingCounter("total-connections-opened", this, () => ConnectionsOpened) { DisplayName = "Total connections opened" }; + _openConnectionCounter ??= new PollingCounter("current-open-connections", this, () => ConnectionsOpened - ConnectionsClosed) { DisplayName = "Current open connections count" }; - _channelOpenedCounter ??= new PollingCounter("total-channels-opened", this, () => ChannelsOpened) { DisplayName = "Total channels opened" }; - _openChannelCounter ??= new PollingCounter("current-open-channels", this, () => ChannelsOpened - ChannelsClosed) { DisplayName = "Current open channels count" }; + _channelOpenedCounter ??= new PollingCounter("total-channels-opened", this, () => ChannelsOpened) { DisplayName = "Total channels opened" }; + _openChannelCounter ??= new PollingCounter("current-open-channels", this, () => ChannelsOpened - ChannelsClosed) { DisplayName = "Current open channels count" }; - _bytesSentCounter ??= new IncrementingPollingCounter("bytes-sent-rate", this, () => Interlocked.Read(ref BytesSent)) { DisplayName = "Byte sending rate", DisplayUnits = "B", DisplayRateTimeScale = new TimeSpan(0, 0, 1) }; - _bytesReceivedCounter ??= new IncrementingPollingCounter("bytes-received-rate", this, () => Interlocked.Read(ref BytesReceived)) { DisplayName = "Byte receiving rate", DisplayUnits = "B", DisplayRateTimeScale = new TimeSpan(0, 0, 1) }; + _bytesSentCounter ??= new IncrementingPollingCounter("bytes-sent-rate", this, () => Interlocked.Read(ref BytesSent)) { DisplayName = "Byte sending rate", DisplayUnits = "B", DisplayRateTimeScale = new TimeSpan(0, 0, 1) }; + _bytesReceivedCounter ??= new IncrementingPollingCounter("bytes-received-rate", this, () => Interlocked.Read(ref BytesReceived)) { DisplayName = "Byte receiving rate", DisplayUnits = "B", DisplayRateTimeScale = new TimeSpan(0, 0, 1) }; - _commandSentCounter ??= new IncrementingPollingCounter("AMQP-method-sent-rate", this, () => Interlocked.Read(ref CommandsSent)) { DisplayName = "AMQP method sending rate", DisplayUnits = "B", DisplayRateTimeScale = new TimeSpan(0, 0, 1) }; - _commandReceivedCounter ??= new IncrementingPollingCounter("AMQP-method-received-rate", this, () => Interlocked.Read(ref CommandsReceived)) { DisplayName = "AMQP method receiving rate", DisplayUnits = "B", DisplayRateTimeScale = new TimeSpan(0, 0, 1) }; + _commandSentCounter ??= new IncrementingPollingCounter("AMQP-method-sent-rate", this, () => Interlocked.Read(ref CommandsSent)) { DisplayName = "AMQP method sending rate", DisplayUnits = "B", DisplayRateTimeScale = new TimeSpan(0, 0, 1) }; + _commandReceivedCounter ??= new IncrementingPollingCounter("AMQP-method-received-rate", this, () => Interlocked.Read(ref CommandsReceived)) { DisplayName = "AMQP method receiving rate", DisplayUnits = "B", DisplayRateTimeScale = new TimeSpan(0, 0, 1) }; + } } - } #endif - [NonEvent] - public void ConnectionOpened() - { - Interlocked.Increment(ref ConnectionsOpened); - } + [NonEvent] + public void ConnectionOpened() + { + Interlocked.Increment(ref ConnectionsOpened); + } - [NonEvent] - public void ConnectionClosed() - { - Interlocked.Increment(ref ConnectionsClosed); - } + [NonEvent] + public void ConnectionClosed() + { + Interlocked.Increment(ref ConnectionsClosed); + } - [NonEvent] - public void ChannelOpened() - { - Interlocked.Increment(ref ChannelsOpened); - } + [NonEvent] + public void ChannelOpened() + { + Interlocked.Increment(ref ChannelsOpened); + } - [NonEvent] - public void ChannelClosed() - { - Interlocked.Increment(ref ChannelsClosed); - } + [NonEvent] + public void ChannelClosed() + { + Interlocked.Increment(ref ChannelsClosed); + } - [NonEvent] - public void DataReceived(int byteCount) - { - Interlocked.Add(ref BytesReceived, byteCount); - } + [NonEvent] + public void DataReceived(int byteCount) + { + Interlocked.Add(ref BytesReceived, byteCount); + } - [NonEvent] - public void CommandSent(int byteCount) - { - Interlocked.Increment(ref CommandsSent); - Interlocked.Add(ref BytesSent, byteCount); - } + [NonEvent] + public void CommandSent(int byteCount) + { + Interlocked.Increment(ref CommandsSent); + Interlocked.Add(ref BytesSent, byteCount); + } - [NonEvent] - public void CommandReceived() - { - Interlocked.Increment(ref CommandsReceived); + [NonEvent] + public void CommandReceived() + { + Interlocked.Increment(ref CommandsReceived); + } } } diff --git a/projects/RabbitMQ.Client/client/logging/RabbitMqClientEventSource.cs b/projects/RabbitMQ.Client/client/logging/RabbitMqClientEventSource.cs index 126d32c2c5..d7ddc75387 100644 --- a/projects/RabbitMQ.Client/client/logging/RabbitMqClientEventSource.cs +++ b/projects/RabbitMQ.Client/client/logging/RabbitMqClientEventSource.cs @@ -32,60 +32,61 @@ using System; using System.Diagnostics.Tracing; -namespace RabbitMQ.Client.Logging; - -#nullable enable -internal sealed partial class RabbitMqClientEventSource : EventSource +namespace RabbitMQ.Client.Logging { - public static readonly RabbitMqClientEventSource Log = new RabbitMqClientEventSource(); - - public RabbitMqClientEventSource() - : base("rabbitmq-client") +#nullable enable + internal sealed partial class RabbitMqClientEventSource : EventSource { - } + public static readonly RabbitMqClientEventSource Log = new RabbitMqClientEventSource(); - public class Keywords - { - public const EventKeywords Log = (EventKeywords)1; - } + public RabbitMqClientEventSource() + : base("rabbitmq-client") + { + } - [Event(1, Message = "INFO", Keywords = Keywords.Log, Level = EventLevel.Informational)] - public void Info(string message) - { - if (IsEnabled()) - WriteEvent(1, message); - } + public class Keywords + { + public const EventKeywords Log = (EventKeywords)1; + } - [Event(2, Message = "WARN", Keywords = Keywords.Log, Level = EventLevel.Warning)] - public void Warn(string message) - { - if (IsEnabled()) - WriteEvent(2, message); - } + [Event(1, Message = "INFO", Keywords = Keywords.Log, Level = EventLevel.Informational)] + public void Info(string message) + { + if (IsEnabled()) + WriteEvent(1, message); + } + + [Event(2, Message = "WARN", Keywords = Keywords.Log, Level = EventLevel.Warning)] + public void Warn(string message) + { + if (IsEnabled()) + WriteEvent(2, message); + } #if NET452 - [Event(3, Message = "ERROR", Keywords = Keywords.Log, Level = EventLevel.Error)] - public void Error(string message, string detail) - { - if(IsEnabled()) - this.WriteEvent(3, message, detail); - } + [Event(3, Message = "ERROR", Keywords = Keywords.Log, Level = EventLevel.Error)] + public void Error(string message, string detail) + { + if(IsEnabled()) + this.WriteEvent(3, message, detail); + } #else - [Event(3, Message = "ERROR", Keywords = Keywords.Log, Level = EventLevel.Error)] - public void Error(string message, RabbitMqExceptionDetail ex) - { - if (IsEnabled()) - WriteEvent(3, message, ex); - } + [Event(3, Message = "ERROR", Keywords = Keywords.Log, Level = EventLevel.Error)] + public void Error(string message, RabbitMqExceptionDetail ex) + { + if (IsEnabled()) + WriteEvent(3, message, ex); + } #endif - [NonEvent] - public void Error(string message, Exception ex) - { + [NonEvent] + public void Error(string message, Exception ex) + { #if NET452 - Error(message, ex.ToString()); + Error(message, ex.ToString()); #else - Error(message, new RabbitMqExceptionDetail(ex)); + Error(message, new RabbitMqExceptionDetail(ex)); #endif + } } } diff --git a/projects/RabbitMQ.Client/client/logging/RabbitMqExceptionDetail.cs b/projects/RabbitMQ.Client/client/logging/RabbitMqExceptionDetail.cs index 72ff38e40d..77476881fc 100644 --- a/projects/RabbitMQ.Client/client/logging/RabbitMqExceptionDetail.cs +++ b/projects/RabbitMQ.Client/client/logging/RabbitMqExceptionDetail.cs @@ -33,43 +33,44 @@ using System.Collections.Generic; using System.Diagnostics.Tracing; -namespace RabbitMQ.Client.Logging; - +namespace RabbitMQ.Client.Logging +{ #if NET452 #else -[EventData] + [EventData] #endif -public class RabbitMqExceptionDetail -{ - public RabbitMqExceptionDetail(Exception ex) + public class RabbitMqExceptionDetail { - Type = ex.GetType().FullName; - Message = ex.Message; - StackTrace = ex.StackTrace; - if (ex.InnerException != null) + public RabbitMqExceptionDetail(Exception ex) { - InnerException = ex.InnerException.ToString(); + Type = ex.GetType().FullName; + Message = ex.Message; + StackTrace = ex.StackTrace; + if (ex.InnerException != null) + { + InnerException = ex.InnerException.ToString(); + } } - } - public RabbitMqExceptionDetail(IDictionary ex) - { - Type = ex["Type"].ToString(); - Message = ex["Message"].ToString(); - StackTrace = ex["StackTrace"].ToString(); - if (ex.TryGetValue("InnerException", out object inner)) + public RabbitMqExceptionDetail(IDictionary ex) { - InnerException = inner.ToString(); + Type = ex["Type"].ToString(); + Message = ex["Message"].ToString(); + StackTrace = ex["StackTrace"].ToString(); + if (ex.TryGetValue("InnerException", out object inner)) + { + InnerException = inner.ToString(); + } } - } - public string Type { get; } - public string Message { get; } - public string StackTrace { get; } - public string InnerException { get; } + public string Type { get; } + public string Message { get; } + public string StackTrace { get; } + public string InnerException { get; } - public override string ToString() - { - return $"Exception: {Type}\r\n{Message}\r\n\r\n{StackTrace}\r\nInnerException:\r\n{InnerException}"; + public override string ToString() + { + return $"Exception: {Type}\r\n{Message}\r\n\r\n{StackTrace}\r\nInnerException:\r\n{InnerException}"; + } } } diff --git a/projects/RabbitMQ.Client/util/BlockingCell.cs b/projects/RabbitMQ.Client/util/BlockingCell.cs index bd2e06c7f5..8f7c0d2736 100644 --- a/projects/RabbitMQ.Client/util/BlockingCell.cs +++ b/projects/RabbitMQ.Client/util/BlockingCell.cs @@ -32,59 +32,60 @@ using System; using System.Threading; -namespace RabbitMQ.Util; - -///A thread-safe single-assignment reference cell. -/// -///A fresh BlockingCell holds no value (is empty). Any thread -///reading the Value property when the cell is empty will block -///until a value is made available by some other thread. The Value -///property can only be set once - on the first call, the -///BlockingCell is considered full, and made immutable. Further -///attempts to set Value result in a thrown -///InvalidOperationException. -/// -internal class BlockingCell +namespace RabbitMQ.Util { - private readonly ManualResetEventSlim _manualResetEventSlim = new ManualResetEventSlim(false); - private T _value = default; - - public void ContinueWithValue(T value) - { - _value = value; - _manualResetEventSlim.Set(); - } - - ///Retrieve the cell's value, waiting for the given - ///timeout if no value is immediately available. + ///A thread-safe single-assignment reference cell. /// - /// - /// If a value is present in the cell at the time the call is - /// made, the call will return immediately. Otherwise, the - /// calling thread blocks until either a value appears, or - /// operation times out. - /// - /// - /// If no value was available before the timeout, an exception - /// is thrown. - /// + ///A fresh BlockingCell holds no value (is empty). Any thread + ///reading the Value property when the cell is empty will block + ///until a value is made available by some other thread. The Value + ///property can only be set once - on the first call, the + ///BlockingCell is considered full, and made immutable. Further + ///attempts to set Value result in a thrown + ///InvalidOperationException. /// - /// - public T WaitForValue(TimeSpan timeout) + internal class BlockingCell { - if (_manualResetEventSlim.Wait(timeout)) + private readonly ManualResetEventSlim _manualResetEventSlim = new ManualResetEventSlim(false); + private T _value = default; + + public void ContinueWithValue(T value) { - return _value; + _value = value; + _manualResetEventSlim.Set(); } - throw new TimeoutException(); - } - ///Retrieve the cell's value, blocking if none exists - ///at present, or supply a value to an empty cell, thereby - ///filling it. - /// - public T WaitForValue() - { - return WaitForValue(TimeSpan.FromMinutes(60)); + ///Retrieve the cell's value, waiting for the given + ///timeout if no value is immediately available. + /// + /// + /// If a value is present in the cell at the time the call is + /// made, the call will return immediately. Otherwise, the + /// calling thread blocks until either a value appears, or + /// operation times out. + /// + /// + /// If no value was available before the timeout, an exception + /// is thrown. + /// + /// + /// + public T WaitForValue(TimeSpan timeout) + { + if (_manualResetEventSlim.Wait(timeout)) + { + return _value; + } + throw new TimeoutException(); + } + + ///Retrieve the cell's value, blocking if none exists + ///at present, or supply a value to an empty cell, thereby + ///filling it. + /// + public T WaitForValue() + { + return WaitForValue(TimeSpan.FromMinutes(60)); + } } } diff --git a/projects/RabbitMQ.Client/util/Either.cs b/projects/RabbitMQ.Client/util/Either.cs index dd52d98dbf..6ef9bdbeee 100644 --- a/projects/RabbitMQ.Client/util/Either.cs +++ b/projects/RabbitMQ.Client/util/Either.cs @@ -29,45 +29,46 @@ // Copyright (c) 2007-2020 VMware, Inc. All rights reserved. //--------------------------------------------------------------------------- -namespace RabbitMQ.Util; - -///Used internally by class Either. -internal enum EitherAlternative +namespace RabbitMQ.Util { - Left, - Right -} + ///Used internally by class Either. + internal enum EitherAlternative + { + Left, + Right + } -///Models the disjoint union of two alternatives, a -///"left" alternative and a "right" alternative. -///Borrowed from ML, Haskell etc. -internal class Either -{ - ///Private constructor. Use the static methods Left, Right instead. - private Either(EitherAlternative alternative, in L valueL, R valueR) + ///Models the disjoint union of two alternatives, a + ///"left" alternative and a "right" alternative. + ///Borrowed from ML, Haskell etc. + internal class Either { - Alternative = alternative; - LeftValue = valueL; - RightValue = valueR; - } + ///Private constructor. Use the static methods Left, Right instead. + private Either(EitherAlternative alternative, in L valueL, R valueR) + { + Alternative = alternative; + LeftValue = valueL; + RightValue = valueR; + } - ///Retrieve the alternative represented by this instance. - public EitherAlternative Alternative { get; } + ///Retrieve the alternative represented by this instance. + public EitherAlternative Alternative { get; } - ///Retrieve the value carried by this instance. - public L LeftValue { get; } - public R RightValue { get; } + ///Retrieve the value carried by this instance. + public L LeftValue { get; } + public R RightValue { get; } - ///Constructs an Either instance representing a Left alternative. - public static Either Left(in L value) - { - return new Either(EitherAlternative.Left, value, default); - } + ///Constructs an Either instance representing a Left alternative. + public static Either Left(in L value) + { + return new Either(EitherAlternative.Left, value, default); + } - ///Constructs an Either instance representing a Right alternative. - public static Either Right(R value) - { - return new Either(EitherAlternative.Right, default, value); + ///Constructs an Either instance representing a Right alternative. + public static Either Right(R value) + { + return new Either(EitherAlternative.Right, default, value); + } } } diff --git a/projects/RabbitMQ.Client/util/IntAllocator.cs b/projects/RabbitMQ.Client/util/IntAllocator.cs index 93556413b6..707838f6d8 100644 --- a/projects/RabbitMQ.Client/util/IntAllocator.cs +++ b/projects/RabbitMQ.Client/util/IntAllocator.cs @@ -32,180 +32,181 @@ using System; using System.Diagnostics; -namespace RabbitMQ.Util; - -/** -* A class for allocating integer IDs in a given range. -*/ -internal class IntAllocator +namespace RabbitMQ.Util { - private readonly int[] _unsorted; - private IntervalList _base; - private int _unsortedCount = 0; - /** - * A class representing a list of inclusive intervals - */ - - /** - * Creates an IntAllocator allocating integer IDs within the inclusive range [start, end] - */ - - public IntAllocator(int start, int end) + * A class for allocating integer IDs in a given range. + */ + internal class IntAllocator { - if (start > end) - { - throw new ArgumentException($"illegal range [{start}, {end}]"); - } + private readonly int[] _unsorted; + private IntervalList _base; + private int _unsortedCount = 0; - // Fairly arbitrary heuristic for a good size for the unsorted set. - _unsorted = new int[Math.Max(32, (int)Math.Sqrt(end - start))]; - _base = new IntervalList(start, end); - } + /** + * A class representing a list of inclusive intervals + */ - /** - * Allocate a fresh integer from the range, or return -1 if no more integers - * are available. This operation is guaranteed to run in O(1) - */ + /** + * Creates an IntAllocator allocating integer IDs within the inclusive range [start, end] + */ - public int Allocate() - { - if (_unsortedCount > 0) + public IntAllocator(int start, int end) { - return _unsorted[--_unsortedCount]; + if (start > end) + { + throw new ArgumentException($"illegal range [{start}, {end}]"); + } + + // Fairly arbitrary heuristic for a good size for the unsorted set. + _unsorted = new int[Math.Max(32, (int)Math.Sqrt(end - start))]; + _base = new IntervalList(start, end); } - else if (_base != null) + + /** + * Allocate a fresh integer from the range, or return -1 if no more integers + * are available. This operation is guaranteed to run in O(1) + */ + + public int Allocate() { - int result = _base.Start; - if (_base.Start == _base.End) + if (_unsortedCount > 0) { - _base = _base.Next; + return _unsorted[--_unsortedCount]; + } + else if (_base != null) + { + int result = _base.Start; + if (_base.Start == _base.End) + { + _base = _base.Next; + } + else + { + _base.Start++; + } + return result; } else { - _base.Start++; + return -1; } - return result; - } - else - { - return -1; } - } - /** - * Make the provided integer available for allocation again. This operation - * runs in amortized O(sqrt(range size)) time: About every sqrt(range size) - * operations will take O(range_size + number of intervals) to complete and - * the rest run in constant time. - * - * No error checking is performed, so if you double Free or Free an integer - * that was not originally Allocated the results are undefined. Sorry. - */ - - public void Free(int id) - { - if (_unsortedCount >= _unsorted.Length) + /** + * Make the provided integer available for allocation again. This operation + * runs in amortized O(sqrt(range size)) time: About every sqrt(range size) + * operations will take O(range_size + number of intervals) to complete and + * the rest run in constant time. + * + * No error checking is performed, so if you double Free or Free an integer + * that was not originally Allocated the results are undefined. Sorry. + */ + + public void Free(int id) { - Flush(); + if (_unsortedCount >= _unsorted.Length) + { + Flush(); + } + _unsorted[_unsortedCount++] = id; } - _unsorted[_unsortedCount++] = id; - } - private void Flush() - { - if (_unsortedCount > 0) + private void Flush() { - _base = IntervalList.Merge(_base, IntervalList.FromArray(_unsorted, _unsortedCount)); - _unsortedCount = 0; + if (_unsortedCount > 0) + { + _base = IntervalList.Merge(_base, IntervalList.FromArray(_unsorted, _unsortedCount)); + _unsortedCount = 0; + } } - } - - - public class IntervalList - { - public int End; - // Invariant: If Next != Null then Next.Start > this.End + 1 - public IntervalList Next; - public int Start; - public IntervalList(int start, int end) + public class IntervalList { - Start = start; - End = end; - } + public int End; - // Destructively merge two IntervalLists. - // Invariant: None of the Intervals in the two lists may overlap - // intervals in this list. + // Invariant: If Next != Null then Next.Start > this.End + 1 + public IntervalList Next; + public int Start; - public static IntervalList FromArray(int[] xs, int length) - { - Array.Sort(xs, 0, length); + public IntervalList(int start, int end) + { + Start = start; + End = end; + } - IntervalList result = null; - IntervalList current = null; + // Destructively merge two IntervalLists. + // Invariant: None of the Intervals in the two lists may overlap + // intervals in this list. - int i = 0; - while (i < length) + public static IntervalList FromArray(int[] xs, int length) { - int start = i; - while ((i < length - 1) && (xs[i + 1] == xs[i] + 1)) + Array.Sort(xs, 0, length); + + IntervalList result = null; + IntervalList current = null; + + int i = 0; + while (i < length) { + int start = i; + while ((i < length - 1) && (xs[i + 1] == xs[i] + 1)) + { + i++; + } + + var interval = new IntervalList(xs[start], xs[i]); + + if (result is null) + { + result = interval; + current = interval; + } + else + { + current.Next = interval; + current = interval; + } i++; } + return result; + } - var interval = new IntervalList(xs[start], xs[i]); - - if (result is null) + public static IntervalList Merge(IntervalList x, IntervalList y) + { + if (x is null) { - result = interval; - current = interval; + return y; } - else + if (y is null) { - current.Next = interval; - current = interval; + return x; } - i++; - } - return result; - } - public static IntervalList Merge(IntervalList x, IntervalList y) - { - if (x is null) - { - return y; - } - if (y is null) - { - return x; - } + if (x.End > y.Start) + { + return Merge(y, x); + } - if (x.End > y.Start) - { - return Merge(y, x); - } + Debug.Assert(x.End != y.Start); - Debug.Assert(x.End != y.Start); + // We now have x, y non-null and x.End < y.Start. + + if (y.Start == x.End + 1) + { + // The two intervals adjoin. Merge them into one and then + // merge the tails. + x.End = y.End; + x.Next = Merge(x.Next, y.Next); + return x; + } - // We now have x, y non-null and x.End < y.Start. + // y belongs in the tail of x. - if (y.Start == x.End + 1) - { - // The two intervals adjoin. Merge them into one and then - // merge the tails. - x.End = y.End; - x.Next = Merge(x.Next, y.Next); + x.Next = Merge(y, x.Next); return x; } - - // y belongs in the tail of x. - - x.Next = Merge(y, x.Next); - return x; } } } diff --git a/projects/RabbitMQ.Client/util/NetworkOrderDeserializer.cs b/projects/RabbitMQ.Client/util/NetworkOrderDeserializer.cs index c032ca576a..a4b5c04aed 100644 --- a/projects/RabbitMQ.Client/util/NetworkOrderDeserializer.cs +++ b/projects/RabbitMQ.Client/util/NetworkOrderDeserializer.cs @@ -2,56 +2,57 @@ using System.Buffers.Binary; using System.Runtime.CompilerServices; -namespace RabbitMQ.Util; - -internal static class NetworkOrderDeserializer +namespace RabbitMQ.Util { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static double ReadDouble(ReadOnlySpan span) - { - return BitConverter.Int64BitsToDouble(BinaryPrimitives.ReadInt64BigEndian(span)); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static short ReadInt16(ReadOnlySpan span) - { - return BinaryPrimitives.ReadInt16BigEndian(span); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static int ReadInt32(ReadOnlySpan span) - { - return BinaryPrimitives.ReadInt32BigEndian(span); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static long ReadInt64(ReadOnlySpan span) - { - return BinaryPrimitives.ReadInt64BigEndian(span); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static float ReadSingle(ReadOnlySpan span) - { - uint num = BinaryPrimitives.ReadUInt32BigEndian(span); - return Unsafe.As(ref num); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static ushort ReadUInt16(ReadOnlySpan span) - { - return BinaryPrimitives.ReadUInt16BigEndian(span); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static uint ReadUInt32(ReadOnlySpan span) - { - return BinaryPrimitives.ReadUInt32BigEndian(span); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static ulong ReadUInt64(ReadOnlySpan span) - { - return BinaryPrimitives.ReadUInt64BigEndian(span); + internal static class NetworkOrderDeserializer + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static double ReadDouble(ReadOnlySpan span) + { + return BitConverter.Int64BitsToDouble(BinaryPrimitives.ReadInt64BigEndian(span)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static short ReadInt16(ReadOnlySpan span) + { + return BinaryPrimitives.ReadInt16BigEndian(span); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static int ReadInt32(ReadOnlySpan span) + { + return BinaryPrimitives.ReadInt32BigEndian(span); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static long ReadInt64(ReadOnlySpan span) + { + return BinaryPrimitives.ReadInt64BigEndian(span); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static float ReadSingle(ReadOnlySpan span) + { + uint num = BinaryPrimitives.ReadUInt32BigEndian(span); + return Unsafe.As(ref num); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static ushort ReadUInt16(ReadOnlySpan span) + { + return BinaryPrimitives.ReadUInt16BigEndian(span); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static uint ReadUInt32(ReadOnlySpan span) + { + return BinaryPrimitives.ReadUInt32BigEndian(span); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static ulong ReadUInt64(ReadOnlySpan span) + { + return BinaryPrimitives.ReadUInt64BigEndian(span); + } } } diff --git a/projects/RabbitMQ.Client/util/NetworkOrderSerializer.cs b/projects/RabbitMQ.Client/util/NetworkOrderSerializer.cs index 9431cf0e6b..20cb7bc2c5 100644 --- a/projects/RabbitMQ.Client/util/NetworkOrderSerializer.cs +++ b/projects/RabbitMQ.Client/util/NetworkOrderSerializer.cs @@ -2,57 +2,58 @@ using System.Buffers.Binary; using System.Runtime.CompilerServices; -namespace RabbitMQ.Util; - -internal static class NetworkOrderSerializer +namespace RabbitMQ.Util { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static void WriteDouble(ref byte destination, double val) - { - long tempVal = Unsafe.As(ref val); - Unsafe.WriteUnaligned(ref destination, BitConverter.IsLittleEndian ? BinaryPrimitives.ReverseEndianness(tempVal) : tempVal); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static void WriteInt16(ref byte destination, short val) - { - Unsafe.WriteUnaligned(ref destination, BitConverter.IsLittleEndian ? BinaryPrimitives.ReverseEndianness(val) : val); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static void WriteInt32(ref byte destination, int val) - { - Unsafe.WriteUnaligned(ref destination, BitConverter.IsLittleEndian ? BinaryPrimitives.ReverseEndianness(val) : val); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static void WriteInt64(ref byte destination, long val) - { - Unsafe.WriteUnaligned(ref destination, BitConverter.IsLittleEndian ? BinaryPrimitives.ReverseEndianness(val) : val); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static void WriteSingle(ref byte destination, float val) - { - int tempVal = Unsafe.As(ref val); - Unsafe.WriteUnaligned(ref destination, BitConverter.IsLittleEndian ? BinaryPrimitives.ReverseEndianness(tempVal) : tempVal); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static void WriteUInt16(ref byte destination, ushort val) - { - Unsafe.WriteUnaligned(ref destination, BitConverter.IsLittleEndian ? BinaryPrimitives.ReverseEndianness(val) : val); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static void WriteUInt32(ref byte destination, uint val) - { - Unsafe.WriteUnaligned(ref destination, BitConverter.IsLittleEndian ? BinaryPrimitives.ReverseEndianness(val) : val); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static void WriteUInt64(ref byte destination, ulong val) - { - Unsafe.WriteUnaligned(ref destination, BitConverter.IsLittleEndian ? BinaryPrimitives.ReverseEndianness(val) : val); + internal static class NetworkOrderSerializer + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static void WriteDouble(ref byte destination, double val) + { + long tempVal = Unsafe.As(ref val); + Unsafe.WriteUnaligned(ref destination, BitConverter.IsLittleEndian ? BinaryPrimitives.ReverseEndianness(tempVal) : tempVal); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static void WriteInt16(ref byte destination, short val) + { + Unsafe.WriteUnaligned(ref destination, BitConverter.IsLittleEndian ? BinaryPrimitives.ReverseEndianness(val) : val); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static void WriteInt32(ref byte destination, int val) + { + Unsafe.WriteUnaligned(ref destination, BitConverter.IsLittleEndian ? BinaryPrimitives.ReverseEndianness(val) : val); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static void WriteInt64(ref byte destination, long val) + { + Unsafe.WriteUnaligned(ref destination, BitConverter.IsLittleEndian ? BinaryPrimitives.ReverseEndianness(val) : val); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static void WriteSingle(ref byte destination, float val) + { + int tempVal = Unsafe.As(ref val); + Unsafe.WriteUnaligned(ref destination, BitConverter.IsLittleEndian ? BinaryPrimitives.ReverseEndianness(tempVal) : tempVal); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static void WriteUInt16(ref byte destination, ushort val) + { + Unsafe.WriteUnaligned(ref destination, BitConverter.IsLittleEndian ? BinaryPrimitives.ReverseEndianness(val) : val); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static void WriteUInt32(ref byte destination, uint val) + { + Unsafe.WriteUnaligned(ref destination, BitConverter.IsLittleEndian ? BinaryPrimitives.ReverseEndianness(val) : val); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static void WriteUInt64(ref byte destination, ulong val) + { + Unsafe.WriteUnaligned(ref destination, BitConverter.IsLittleEndian ? BinaryPrimitives.ReverseEndianness(val) : val); + } } } diff --git a/projects/RabbitMQ.Client/util/TypeExtensions.cs b/projects/RabbitMQ.Client/util/TypeExtensions.cs index a09ff3e344..906bca1293 100644 --- a/projects/RabbitMQ.Client/util/TypeExtensions.cs +++ b/projects/RabbitMQ.Client/util/TypeExtensions.cs @@ -2,67 +2,68 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -namespace RabbitMQ; - -internal static class TypeExtensions +namespace RabbitMQ { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ref byte GetStart(this ReadOnlySpan span) + internal static class TypeExtensions { - return ref MemoryMarshal.GetReference(span); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ref byte GetStart(this ReadOnlySpan span) + { + return ref MemoryMarshal.GetReference(span); + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ref byte GetStart(this byte[] array) - { - return ref Unsafe.AsRef(array[0]); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ref byte GetStart(this byte[] array) + { + return ref Unsafe.AsRef(array[0]); + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ref byte GetStart(this Span span) - { - return ref MemoryMarshal.GetReference(span); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ref byte GetStart(this Span span) + { + return ref MemoryMarshal.GetReference(span); + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ref byte GetOffset(this ReadOnlySpan span, int offset) - { - return ref span.GetStart().GetOffset(offset); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ref byte GetOffset(this ReadOnlySpan span, int offset) + { + return ref span.GetStart().GetOffset(offset); + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ref byte GetOffset(this Span span, int offset) - { - return ref span.GetStart().GetOffset(offset); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ref byte GetOffset(this Span span, int offset) + { + return ref span.GetStart().GetOffset(offset); + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ref byte GetOffset(this ref byte source, int offset) - { - return ref Unsafe.Add(ref source, offset); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ref byte GetOffset(this ref byte source, int offset) + { + return ref Unsafe.Add(ref source, offset); + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool IsBitSet(this in byte value, byte bitPosition) - { - return (value & (1 << bitPosition)) != 0; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool IsBitSet(this in byte value, byte bitPosition) + { + return (value & (1 << bitPosition)) != 0; + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void SetBit(this ref byte value, byte bitPosition) - { - value |= (byte)(1 << bitPosition); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SetBit(this ref byte value, byte bitPosition) + { + value |= (byte)(1 << bitPosition); + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static byte ToByte(this ref bool source) - { - return Unsafe.As(ref source); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static byte ToByte(this ref bool source) + { + return Unsafe.As(ref source); + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool ToBool(this ref byte source) - { - return Unsafe.As(ref source); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool ToBool(this ref byte source) + { + return Unsafe.As(ref source); + } } }