diff --git a/Source/MQTTnet.AspnetCore/MQTTnet.AspNetCore.csproj b/Source/MQTTnet.AspnetCore/MQTTnet.AspNetCore.csproj index a76986e1..b8edf8ae 100644 --- a/Source/MQTTnet.AspnetCore/MQTTnet.AspNetCore.csproj +++ b/Source/MQTTnet.AspnetCore/MQTTnet.AspNetCore.csproj @@ -19,7 +19,11 @@ - + + + + + diff --git a/Source/MQTTnet.AspnetCore/MqttConnectionContext.cs b/Source/MQTTnet.AspnetCore/MqttConnectionContext.cs index 4aa0446a..47efc013 100644 --- a/Source/MQTTnet.AspnetCore/MqttConnectionContext.cs +++ b/Source/MQTTnet.AspnetCore/MqttConnectionContext.cs @@ -11,11 +11,18 @@ using System.Security.Cryptography.X509Certificates; using System.Threading; using System.Threading.Tasks; using MQTTnet.AspNetCore.Extensions; +using MQTTnet.Internal; namespace MQTTnet.AspNetCore { - public class MqttConnectionContext : IMqttChannelAdapter + public sealed class MqttConnectionContext : IMqttChannelAdapter { + readonly AsyncLock _writerLock = new AsyncLock(); + readonly SpanBasedMqttPacketBodyReader _reader; + + PipeReader _input; + PipeWriter _output; + public MqttConnectionContext(MqttPacketFormatterAdapter packetFormatterAdapter, ConnectionContext connection) { PacketFormatterAdapter = packetFormatterAdapter ?? throw new ArgumentNullException(nameof(packetFormatterAdapter)); @@ -30,10 +37,6 @@ namespace MQTTnet.AspNetCore _reader = new SpanBasedMqttPacketBodyReader(); } - private PipeReader _input; - private PipeWriter _output; - private readonly SpanBasedMqttPacketBodyReader _reader; - public string Endpoint { get @@ -58,9 +61,8 @@ namespace MQTTnet.AspNetCore public X509Certificate2 ClientCertificate => Http?.HttpContext?.Connection?.ClientCertificate; - private IHttpContextFeature Http => Connection.Features.Get(); - public ConnectionContext Connection { get; } + public MqttPacketFormatterAdapter PacketFormatterAdapter { get; } public long BytesSent { get; set; } @@ -69,7 +71,7 @@ namespace MQTTnet.AspNetCore public Action ReadingPacketStartedCallback { get; set; } public Action ReadingPacketCompletedCallback { get; set; } - private readonly SemaphoreSlim _writerSemaphore = new SemaphoreSlim(1, 1); + IHttpContextFeature Http => Connection.Features.Get(); public async Task ConnectAsync(TimeSpan timeout, CancellationToken cancellationToken) { @@ -165,8 +167,7 @@ namespace MQTTnet.AspNetCore var msg = buffer.AsMemory(); var output = _output; - await _writerSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); - try + using (await _writerLock.WaitAsync(cancellationToken).ConfigureAwait(false)) { var result = await output.WriteAsync(msg, cancellationToken).ConfigureAwait(false); if (result.IsCompleted) @@ -176,10 +177,6 @@ namespace MQTTnet.AspNetCore PacketFormatterAdapter.FreeBuffer(); } - finally - { - _writerSemaphore.Release(); - } } public void Dispose() diff --git a/Source/MQTTnet.AspnetCore/MqttSubProtocolSelector.cs b/Source/MQTTnet.AspnetCore/MqttSubProtocolSelector.cs index d400ab3d..6386b4fe 100644 --- a/Source/MQTTnet.AspnetCore/MqttSubProtocolSelector.cs +++ b/Source/MQTTnet.AspnetCore/MqttSubProtocolSelector.cs @@ -1,12 +1,29 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; +using Microsoft.AspNetCore.Http; namespace MQTTnet.AspNetCore { public static class MqttSubProtocolSelector { + public static string SelectSubProtocol(HttpRequest request) + { + if (request == null) throw new ArgumentNullException(nameof(request)); + + string subProtocol = null; + if (request.Headers.TryGetValue("Sec-WebSocket-Protocol", out var requestedSubProtocolValues)) + { + subProtocol = SelectSubProtocol(requestedSubProtocolValues); + } + + return subProtocol; + } + public static string SelectSubProtocol(IList requestedSubProtocolValues) { + if (requestedSubProtocolValues == null) throw new ArgumentNullException(nameof(requestedSubProtocolValues)); + // Order the protocols to also match "mqtt", "mqttv-3.1", "mqttv-3.11" etc. return requestedSubProtocolValues .OrderByDescending(p => p.Length) diff --git a/Source/MQTTnet.Server/MQTTnet.Server.csproj b/Source/MQTTnet.Server/MQTTnet.Server.csproj index 8f2ac2ef..4f07a09d 100644 --- a/Source/MQTTnet.Server/MQTTnet.Server.csproj +++ b/Source/MQTTnet.Server/MQTTnet.Server.csproj @@ -39,12 +39,12 @@ - - - + + + - - + + diff --git a/Source/MQTTnet/Client/IMqttClientFactory.cs b/Source/MQTTnet/Client/IMqttClientFactory.cs index bae75aca..b256e742 100644 --- a/Source/MQTTnet/Client/IMqttClientFactory.cs +++ b/Source/MQTTnet/Client/IMqttClientFactory.cs @@ -1,5 +1,7 @@ -using MQTTnet.Adapter; +using System; +using MQTTnet.Adapter; using MQTTnet.Diagnostics; +using MQTTnet.LowLevelClient; namespace MQTTnet.Client { @@ -7,6 +9,14 @@ namespace MQTTnet.Client { IMqttFactory UseClientAdapterFactory(IMqttClientAdapterFactory clientAdapterFactory); + ILowLevelMqttClient CreateLowLevelMqttClient(); + + ILowLevelMqttClient CreateLowLevelMqttClient(IMqttNetLogger logger); + + ILowLevelMqttClient CreateLowLevelMqttClient(IMqttClientAdapterFactory clientAdapterFactory); + + ILowLevelMqttClient CreateLowLevelMqttClient(IMqttNetLogger logger, IMqttClientAdapterFactory clientAdapterFactory); + IMqttClient CreateMqttClient(); IMqttClient CreateMqttClient(IMqttNetLogger logger); diff --git a/Source/MQTTnet/IMqttFactory.cs b/Source/MQTTnet/IMqttFactory.cs index 487d77f4..8c0e5af3 100644 --- a/Source/MQTTnet/IMqttFactory.cs +++ b/Source/MQTTnet/IMqttFactory.cs @@ -1,4 +1,5 @@ -using MQTTnet.Client; +using System.Collections.Generic; +using MQTTnet.Client; using MQTTnet.Diagnostics; using MQTTnet.Server; @@ -7,5 +8,7 @@ namespace MQTTnet public interface IMqttFactory : IMqttClientFactory, IMqttServerFactory { IMqttNetLogger DefaultLogger { get; } + + IDictionary Properties { get; } } } diff --git a/Source/MQTTnet/Internal/AsyncLock.cs b/Source/MQTTnet/Internal/AsyncLock.cs index 17d7404f..210364ab 100644 --- a/Source/MQTTnet/Internal/AsyncLock.cs +++ b/Source/MQTTnet/Internal/AsyncLock.cs @@ -5,10 +5,10 @@ using System.Threading.Tasks; namespace MQTTnet.Internal { // From Stephen Toub (https://blogs.msdn.microsoft.com/pfxteam/2012/02/12/building-async-coordination-primitives-part-6-asynclock/) - public class AsyncLock : IDisposable + public sealed class AsyncLock : IDisposable { - private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1); - private readonly Task _releaser; + readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1); + readonly Task _releaser; public AsyncLock() { @@ -39,9 +39,9 @@ namespace MQTTnet.Internal _semaphore?.Dispose(); } - private class Releaser : IDisposable + class Releaser : IDisposable { - private readonly AsyncLock _toRelease; + readonly AsyncLock _toRelease; internal Releaser(AsyncLock toRelease) { diff --git a/Source/MQTTnet/MqttFactory.cs b/Source/MQTTnet/MqttFactory.cs index 18193e1a..e49488ac 100644 --- a/Source/MQTTnet/MqttFactory.cs +++ b/Source/MQTTnet/MqttFactory.cs @@ -6,6 +6,7 @@ using MQTTnet.LowLevelClient; using MQTTnet.Server; using System; using System.Collections.Generic; +using System.Linq; namespace MQTTnet { @@ -25,6 +26,13 @@ namespace MQTTnet public IMqttNetLogger DefaultLogger { get; } + public IList> DefaultServerAdapters { get; } = new List> + { + factory => new MqttTcpServerAdapter(factory.DefaultLogger) + }; + + public IDictionary Properties { get; } = new Dictionary(); + public IMqttFactory UseClientAdapterFactory(IMqttClientAdapterFactory clientAdapterFactory) { _clientAdapterFactory = clientAdapterFactory ?? throw new ArgumentNullException(nameof(clientAdapterFactory)); @@ -50,10 +58,10 @@ namespace MQTTnet return new LowLevelMqttClient(_clientAdapterFactory, DefaultLogger); } - public ILowLevelMqttClient CreateLowLevelMqttClient(IMqttNetLogger logger, IMqttClientAdapterFactory clientAdapterFactoryy) + public ILowLevelMqttClient CreateLowLevelMqttClient(IMqttNetLogger logger, IMqttClientAdapterFactory clientAdapterFactory) { if (logger == null) throw new ArgumentNullException(nameof(logger)); - if (clientAdapterFactoryy == null) throw new ArgumentNullException(nameof(clientAdapterFactoryy)); + if (clientAdapterFactory == null) throw new ArgumentNullException(nameof(clientAdapterFactory)); return new LowLevelMqttClient(_clientAdapterFactory, logger); } @@ -94,7 +102,8 @@ namespace MQTTnet { if (logger == null) throw new ArgumentNullException(nameof(logger)); - return CreateMqttServer(new List { new MqttTcpServerAdapter(logger) }, logger); + var serverAdapters = DefaultServerAdapters.Select(a => a.Invoke(this)); + return CreateMqttServer(serverAdapters, logger); } public IMqttServer CreateMqttServer(IEnumerable serverAdapters, IMqttNetLogger logger) diff --git a/Source/MQTTnet/Server/IMqttServerFactory.cs b/Source/MQTTnet/Server/IMqttServerFactory.cs index e8c7d401..39efaa3d 100644 --- a/Source/MQTTnet/Server/IMqttServerFactory.cs +++ b/Source/MQTTnet/Server/IMqttServerFactory.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using MQTTnet.Adapter; using MQTTnet.Diagnostics; @@ -6,6 +7,8 @@ namespace MQTTnet.Server { public interface IMqttServerFactory { + IList> DefaultServerAdapters { get; } + IMqttServer CreateMqttServer(); IMqttServer CreateMqttServer(IMqttNetLogger logger); diff --git a/Tests/MQTTnet.AspNetCore.Tests/MQTTnet.AspNetCore.Tests.csproj b/Tests/MQTTnet.AspNetCore.Tests/MQTTnet.AspNetCore.Tests.csproj index 4a7526b8..20094884 100644 --- a/Tests/MQTTnet.AspNetCore.Tests/MQTTnet.AspNetCore.Tests.csproj +++ b/Tests/MQTTnet.AspNetCore.Tests/MQTTnet.AspNetCore.Tests.csproj @@ -6,7 +6,7 @@ - + diff --git a/Tests/MQTTnet.Benchmarks/MQTTnet.Benchmarks.csproj b/Tests/MQTTnet.Benchmarks/MQTTnet.Benchmarks.csproj index f15a4872..e4c8e2f9 100644 --- a/Tests/MQTTnet.Benchmarks/MQTTnet.Benchmarks.csproj +++ b/Tests/MQTTnet.Benchmarks/MQTTnet.Benchmarks.csproj @@ -10,7 +10,7 @@ - + diff --git a/Tests/MQTTnet.Core.Tests/MQTTnet.Tests.csproj b/Tests/MQTTnet.Core.Tests/MQTTnet.Tests.csproj index a4b7702b..c7486d37 100644 --- a/Tests/MQTTnet.Core.Tests/MQTTnet.Tests.csproj +++ b/Tests/MQTTnet.Core.Tests/MQTTnet.Tests.csproj @@ -8,7 +8,7 @@ - +