From 69fd82e1a9a0d27ec39262ff0332d930fd5c3790 Mon Sep 17 00:00:00 2001 From: Christian Date: Sat, 8 Jan 2022 15:37:37 +0100 Subject: [PATCH] Squashed commit of the following: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 27592f16439c9db1db9c1335dd04b0f1d23f0c1d Author: Christian Date: Sat Jan 8 15:36:35 2022 +0100 Update MQTTnet.nuspec commit c6f4b594382f33089946f6169921cb651a42bfda Author: Christian Date: Sat Jan 8 15:35:47 2022 +0100 Increase delay for Keep Alive checks to decrease CPU load. commit b362b2afc203c9c127b2e8adab03e6b96d25fbc1 Author: Christian Date: Sat Jan 8 14:35:25 2022 +0100 Make logger parameters generic. commit 7a72a8d562543f6cf0a30120cc783a127285853b Author: Christian Date: Sat Jan 8 14:07:57 2022 +0100 Update MQTTnet.nuspec commit bd40e10a666581df1f909b74cea097c189a6df2d Author: Günther Foidl Date: Sat Jan 8 14:00:39 2022 +0100 Elide repeated Action-delegate allocation by caching it (#1324) * Elide repeated Action-delegate allocation by caching it Here C# compiler has too little knowledge about the usage of the delegate, we know better so cache it on our own to avoid the repeated allocation. * Use conditional compilation commit 4b44a2b2b18b7215cd8744380de2912657e284e5 Author: Christian Date: Fri Jan 7 18:01:03 2022 +0100 Remove appveyor. commit 215f24a95be8381dbaabec1535600f01e90cf5ca Author: Christian Date: Fri Jan 7 17:52:16 2022 +0100 Create CODE-OF-CONDUCT.md --- Source/MQTTnet/Client/MqttClient.cs | 4 +- .../Diagnostics/Logger/IMqttNetLogger.cs | 2 + .../Diagnostics/Logger/MqttNetEventLogger.cs | 2 + .../Diagnostics/Logger/MqttNetNullLogger.cs | 2 + .../Diagnostics/Logger/MqttNetSourceLogger.cs | 2 + .../Logger/MqttNetSourceLoggerExtensions.cs | 140 ++++++++++++++++-- .../Implementations/CrossPlatformSocket.cs | 10 +- .../MQTTnet/Implementations/MqttTcpChannel.cs | 36 +++-- .../MQTTnet.Core.Tests/Logger/Logger_Tests.cs | 4 +- .../Logger/SourceLogger_Tests.cs | 2 +- .../MQTTnet.Core.Tests/Mockups/TestLogger.cs | 4 +- 11 files changed, 174 insertions(+), 34 deletions(-) diff --git a/Source/MQTTnet/Client/MqttClient.cs b/Source/MQTTnet/Client/MqttClient.cs index 670467c4c..5a218586a 100644 --- a/Source/MQTTnet/Client/MqttClient.cs +++ b/Source/MQTTnet/Client/MqttClient.cs @@ -489,7 +489,7 @@ async Task TrySendKeepAliveMessagesAsync(CancellationToken cancellationToken) _logger.Verbose("Start sending keep alive packets."); var keepAlivePeriod = Options.KeepAlivePeriod; - + while (!cancellationToken.IsCancellationRequested) { // Values described here: [MQTT-3.1.2-24]. @@ -504,7 +504,7 @@ async Task TrySendKeepAliveMessagesAsync(CancellationToken cancellationToken) // due to some edge cases and was buggy in the past. Now we wait several ms because the // min keep alive value is one second so that the server will wait 1.5 seconds for a PING // packet. - await Task.Delay(TimeSpan.FromMilliseconds(100), cancellationToken).ConfigureAwait(false); + await Task.Delay(250, cancellationToken).ConfigureAwait(false); } } catch (Exception exception) diff --git a/Source/MQTTnet/Diagnostics/Logger/IMqttNetLogger.cs b/Source/MQTTnet/Diagnostics/Logger/IMqttNetLogger.cs index e77d0d11c..669e352ac 100644 --- a/Source/MQTTnet/Diagnostics/Logger/IMqttNetLogger.cs +++ b/Source/MQTTnet/Diagnostics/Logger/IMqttNetLogger.cs @@ -4,6 +4,8 @@ namespace MQTTnet.Diagnostics { public interface IMqttNetLogger { + bool IsEnabled { get; } + void Publish(MqttNetLogLevel logLevel, string source, string message, object[] parameters, Exception exception); } } diff --git a/Source/MQTTnet/Diagnostics/Logger/MqttNetEventLogger.cs b/Source/MQTTnet/Diagnostics/Logger/MqttNetEventLogger.cs index 6e00fa382..d410951cd 100644 --- a/Source/MQTTnet/Diagnostics/Logger/MqttNetEventLogger.cs +++ b/Source/MQTTnet/Diagnostics/Logger/MqttNetEventLogger.cs @@ -16,6 +16,8 @@ public MqttNetEventLogger(string logId = null) public string LogId { get; } + public bool IsEnabled { get; set; } = true; + public void Publish(MqttNetLogLevel level, string source, string message, object[] parameters, Exception exception) { var eventHandler = LogMessagePublished; diff --git a/Source/MQTTnet/Diagnostics/Logger/MqttNetNullLogger.cs b/Source/MQTTnet/Diagnostics/Logger/MqttNetNullLogger.cs index 6e8b97981..ef3cc3b38 100644 --- a/Source/MQTTnet/Diagnostics/Logger/MqttNetNullLogger.cs +++ b/Source/MQTTnet/Diagnostics/Logger/MqttNetNullLogger.cs @@ -7,6 +7,8 @@ namespace MQTTnet.Diagnostics /// public sealed class MqttNetNullLogger : IMqttNetLogger { + public bool IsEnabled { get; } + public void Publish(MqttNetLogLevel logLevel, string source, string message, object[] parameters, Exception exception) { } diff --git a/Source/MQTTnet/Diagnostics/Logger/MqttNetSourceLogger.cs b/Source/MQTTnet/Diagnostics/Logger/MqttNetSourceLogger.cs index 546dad6c7..e912010e4 100644 --- a/Source/MQTTnet/Diagnostics/Logger/MqttNetSourceLogger.cs +++ b/Source/MQTTnet/Diagnostics/Logger/MqttNetSourceLogger.cs @@ -13,6 +13,8 @@ public MqttNetSourceLogger(IMqttNetLogger logger, string source) _source = source; } + public bool IsEnabled => _logger.IsEnabled; + public void Publish(MqttNetLogLevel logLevel, string message, object[] parameters, Exception exception) { _logger.Publish(logLevel, _source, message, parameters, exception); diff --git a/Source/MQTTnet/Diagnostics/Logger/MqttNetSourceLoggerExtensions.cs b/Source/MQTTnet/Diagnostics/Logger/MqttNetSourceLoggerExtensions.cs index a09cdc6d2..77bec8516 100644 --- a/Source/MQTTnet/Diagnostics/Logger/MqttNetSourceLoggerExtensions.cs +++ b/Source/MQTTnet/Diagnostics/Logger/MqttNetSourceLoggerExtensions.cs @@ -4,66 +4,176 @@ namespace MQTTnet.Diagnostics { public static class MqttNetSourceLoggerExtensions { + /* + * The logger uses generic parameters in order to avoid boxing of parameter values like integers etc. + */ + public static MqttNetSourceLogger WithSource(this IMqttNetLogger logger, string source) { if (logger == null) throw new ArgumentNullException(nameof(logger)); - + return new MqttNetSourceLogger(logger, source); } - - public static void Verbose(this MqttNetSourceLogger logger, string message, params object[] parameters) + + public static void Verbose(this MqttNetSourceLogger logger, string message, TParameter1 parameter1) { - logger.Publish(MqttNetLogLevel.Verbose, message, parameters, null); + if (!logger.IsEnabled) + { + return; + } + + logger.Publish(MqttNetLogLevel.Verbose, message, new object[] {parameter1}, null); } - + + public static void Verbose(this MqttNetSourceLogger logger, string message, TParameter1 parameter1, TParameter2 parameter2) + { + if (!logger.IsEnabled) + { + return; + } + + logger.Publish(MqttNetLogLevel.Verbose, message, new object[] {parameter1, parameter2}, null); + } + + public static void Verbose(this MqttNetSourceLogger logger, string message, TParameter1 parameter1, TParameter2 parameter2, + TParameter3 parameter3) + { + if (!logger.IsEnabled) + { + return; + } + + logger.Publish(MqttNetLogLevel.Verbose, message, new object[] {parameter1, parameter2, parameter3}, null); + } + public static void Verbose(this MqttNetSourceLogger logger, string message) { + if (!logger.IsEnabled) + { + return; + } + logger.Publish(MqttNetLogLevel.Verbose, message, null, null); } - public static void Info(this MqttNetSourceLogger logger, string message, params object[] parameters) + public static void Info(this MqttNetSourceLogger logger, string message, TParameter1 parameter1) { - logger.Publish(MqttNetLogLevel.Info, message, parameters, null); + if (!logger.IsEnabled) + { + return; + } + + logger.Publish(MqttNetLogLevel.Info, message, new object[] {parameter1}, null); } + public static void Info(this MqttNetSourceLogger logger, string message, TParameter1 parameter1, TParameter2 parameter2) + { + if (!logger.IsEnabled) + { + return; + } + + logger.Publish(MqttNetLogLevel.Info, message, new object[] {parameter1, parameter2}, null); + } + public static void Info(this MqttNetSourceLogger logger, string message) { + if (!logger.IsEnabled) + { + return; + } + logger.Publish(MqttNetLogLevel.Info, message, null, null); } - public static void Warning(this MqttNetSourceLogger logger, Exception exception, string message, params object[] parameters) + public static void Warning(this MqttNetSourceLogger logger, Exception exception, string message, TParameter1 parameter1) + { + if (!logger.IsEnabled) + { + return; + } + + logger.Publish(MqttNetLogLevel.Warning, message, new object[] {parameter1}, exception); + } + + public static void Warning(this MqttNetSourceLogger logger, Exception exception, string message, TParameter1 parameter1, TParameter2 parameter2) { - logger.Publish(MqttNetLogLevel.Warning, message, parameters, exception); + if (!logger.IsEnabled) + { + return; + } + + logger.Publish(MqttNetLogLevel.Warning, message, new object[] {parameter1, parameter2}, exception); } public static void Warning(this MqttNetSourceLogger logger, Exception exception, string message) { + if (!logger.IsEnabled) + { + return; + } + logger.Publish(MqttNetLogLevel.Warning, message, null, exception); } - public static void Warning(this MqttNetSourceLogger logger, string message, params object[] parameters) + public static void Warning(this MqttNetSourceLogger logger, string message, TParameter1 parameter1) { - logger.Publish(MqttNetLogLevel.Warning, message, parameters, null); + if (!logger.IsEnabled) + { + return; + } + + logger.Publish(MqttNetLogLevel.Warning, message, new object[] {parameter1}, null); } public static void Warning(this MqttNetSourceLogger logger, string message) { + if (!logger.IsEnabled) + { + return; + } + logger.Publish(MqttNetLogLevel.Warning, message, null, null); } - public static void Error(this MqttNetSourceLogger logger, Exception exception, string message, params object[] parameters) + public static void Error(this MqttNetSourceLogger logger, Exception exception, string message, TParameter1 parameter1) { - logger.Publish(MqttNetLogLevel.Error, message, parameters, exception); + if (!logger.IsEnabled) + { + return; + } + + logger.Publish(MqttNetLogLevel.Error, message, new object[] {parameter1}, exception); } + public static void Error(this MqttNetSourceLogger logger, Exception exception, string message, TParameter1 parameter1, TParameter2 parameter2) + { + if (!logger.IsEnabled) + { + return; + } + + logger.Publish(MqttNetLogLevel.Error, message, new object[] {parameter1, parameter2}, exception); + } + public static void Error(this MqttNetSourceLogger logger, Exception exception, string message) { + if (!logger.IsEnabled) + { + return; + } + logger.Publish(MqttNetLogLevel.Error, message, null, exception); } - + public static void Error(this MqttNetSourceLogger logger, string message) { + if (!logger.IsEnabled) + { + return; + } + logger.Publish(MqttNetLogLevel.Error, message, null, null); } } -} +} \ No newline at end of file diff --git a/Source/MQTTnet/Implementations/CrossPlatformSocket.cs b/Source/MQTTnet/Implementations/CrossPlatformSocket.cs index 18d2d8927..86e0be1b7 100644 --- a/Source/MQTTnet/Implementations/CrossPlatformSocket.cs +++ b/Source/MQTTnet/Implementations/CrossPlatformSocket.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.IO; using System.Net; using System.Net.Sockets; @@ -11,12 +11,14 @@ namespace MQTTnet.Implementations public sealed class CrossPlatformSocket : IDisposable { readonly Socket _socket; + readonly Action _socketDisposeAction; NetworkStream _networkStream; public CrossPlatformSocket(AddressFamily addressFamily) { _socket = new Socket(addressFamily, SocketType.Stream, ProtocolType.Tcp); + _socketDisposeAction = _socket.Dispose; } public CrossPlatformSocket() @@ -24,12 +26,16 @@ public CrossPlatformSocket() // Having this constructor is important because avoiding the address family as parameter // will make use of dual mode in the .net framework. _socket = new Socket(SocketType.Stream, ProtocolType.Tcp); + + _socketDisposeAction = _socket.Dispose; } public CrossPlatformSocket(Socket socket) { _socket = socket ?? throw new ArgumentNullException(nameof(socket)); _networkStream = new NetworkStream(socket, true); + + _socketDisposeAction = _socket.Dispose; } public bool NoDelay @@ -112,7 +118,7 @@ public async Task ConnectAsync(string host, int port, CancellationToken cancella _networkStream?.Dispose(); // Workaround for: https://github.com/dotnet/corefx/issues/24430 - using (cancellationToken.Register(() => _socket.Dispose())) + using (cancellationToken.Register(_socketDisposeAction)) { cancellationToken.ThrowIfCancellationRequested(); diff --git a/Source/MQTTnet/Implementations/MqttTcpChannel.cs b/Source/MQTTnet/Implementations/MqttTcpChannel.cs index a8a4aa17a..52a16915b 100644 --- a/Source/MQTTnet/Implementations/MqttTcpChannel.cs +++ b/Source/MQTTnet/Implementations/MqttTcpChannel.cs @@ -18,10 +18,16 @@ public sealed class MqttTcpChannel : IMqttChannel { readonly IMqttClientOptions _clientOptions; readonly MqttClientTcpOptions _tcpOptions; + readonly Action _disposeAction; Stream _stream; - public MqttTcpChannel(IMqttClientOptions clientOptions) + public MqttTcpChannel() + { + _disposeAction = Dispose; + } + + public MqttTcpChannel(IMqttClientOptions clientOptions) : this() { _clientOptions = clientOptions ?? throw new ArgumentNullException(nameof(clientOptions)); _tcpOptions = (MqttClientTcpOptions) clientOptions.ChannelOptions; @@ -29,7 +35,7 @@ public MqttTcpChannel(IMqttClientOptions clientOptions) IsSecureConnection = clientOptions.ChannelOptions?.TlsOptions?.UseTls == true; } - public MqttTcpChannel(Stream stream, string endpoint, X509Certificate2 clientCertificate) + public MqttTcpChannel(Stream stream, string endpoint, X509Certificate2 clientCertificate) : this() { _stream = stream ?? throw new ArgumentNullException(nameof(stream)); @@ -150,11 +156,15 @@ public async Task ReadAsync(byte[] buffer, int offset, int count, Cancellat return 0; } +#if NETCOREAPP3_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER + return await stream.ReadAsync(buffer.AsMemory(offset, count), cancellationToken).ConfigureAwait(false); +#else // Workaround for: https://github.com/dotnet/corefx/issues/24430 - using (cancellationToken.Register(Dispose)) + using (cancellationToken.Register(_disposeAction)) { return await stream.ReadAsync(buffer, offset, count, cancellationToken).ConfigureAwait(false); } +#endif } catch (ObjectDisposedException) { @@ -178,18 +188,22 @@ public async Task WriteAsync(byte[] buffer, int offset, int count, CancellationT try { - // Workaround for: https://github.com/dotnet/corefx/issues/24430 - using (cancellationToken.Register(Dispose)) - { - var stream = _stream; + var stream = _stream; - if (stream == null) - { - throw new MqttCommunicationException("The TCP connection is closed."); - } + if (stream == null) + { + throw new MqttCommunicationException("The TCP connection is closed."); + } +#if NETCOREAPP3_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER + await stream.WriteAsync(buffer.AsMemory(offset, count), cancellationToken).ConfigureAwait(false); +#else + // Workaround for: https://github.com/dotnet/corefx/issues/24430 + using (cancellationToken.Register(_disposeAction)) + { await stream.WriteAsync(buffer, offset, count, cancellationToken).ConfigureAwait(false); } +#endif } catch (ObjectDisposedException) { diff --git a/Tests/MQTTnet.Core.Tests/Logger/Logger_Tests.cs b/Tests/MQTTnet.Core.Tests/Logger/Logger_Tests.cs index 75340826b..adefa4196 100644 --- a/Tests/MQTTnet.Core.Tests/Logger/Logger_Tests.cs +++ b/Tests/MQTTnet.Core.Tests/Logger/Logger_Tests.cs @@ -35,7 +35,7 @@ public void Root_Log_Messages() childLogger.Verbose("Verbose"); childLogger.Info("Info"); - childLogger.Warning(null, "Warning"); + childLogger.Warning((Exception)null, "Warning"); childLogger.Error(null, "Error"); Assert.AreEqual(4, logMessagesCount); @@ -55,7 +55,7 @@ public void Use_Custom_Log_Id() childLogger.Verbose("Verbose"); childLogger.Info("Info"); - childLogger.Warning(null, "Warning"); + childLogger.Warning((Exception)null, "Warning"); childLogger.Error(null, "Error"); } } diff --git a/Tests/MQTTnet.Core.Tests/Logger/SourceLogger_Tests.cs b/Tests/MQTTnet.Core.Tests/Logger/SourceLogger_Tests.cs index 8614d9d31..8f3bf3e6c 100644 --- a/Tests/MQTTnet.Core.Tests/Logger/SourceLogger_Tests.cs +++ b/Tests/MQTTnet.Core.Tests/Logger/SourceLogger_Tests.cs @@ -18,7 +18,7 @@ public void Log_With_Source() }; var sourceLogger = logger.WithSource("The_Source"); - sourceLogger.Info("MESSAGE", null, null); + sourceLogger.Info("MESSAGE", (object)null, (object)null); Assert.AreEqual("The_Source", logMessage.Source); } diff --git a/Tests/MQTTnet.Core.Tests/Mockups/TestLogger.cs b/Tests/MQTTnet.Core.Tests/Mockups/TestLogger.cs index f13e49f0d..962da9997 100644 --- a/Tests/MQTTnet.Core.Tests/Mockups/TestLogger.cs +++ b/Tests/MQTTnet.Core.Tests/Mockups/TestLogger.cs @@ -6,7 +6,9 @@ namespace MQTTnet.Tests.Mockups public sealed class TestLogger : IMqttNetLogger { public event EventHandler LogMessagePublished; - + + public bool IsEnabled { get; } = true; + public void Publish(MqttNetLogLevel logLevel, string source, string message, object[] parameters, Exception exception) { LogMessagePublished?.Invoke(this, new MqttNetLogMessagePublishedEventArgs(new MqttNetLogMessage