@@ -1,30 +0,0 @@ | |||||
using System; | |||||
using MQTTnet.Core.Adapter; | |||||
using MQTTnet.Core.Client; | |||||
using MQTTnet.Core.Diagnostics; | |||||
using MQTTnet.Core.Serializer; | |||||
namespace MQTTnet.Implementations | |||||
{ | |||||
public class MqttCommunicationAdapterFactory : IMqttCommunicationAdapterFactory | |||||
{ | |||||
public IMqttCommunicationAdapter CreateMqttCommunicationAdapter(IMqttClientOptions options) | |||||
{ | |||||
if (options == null) throw new ArgumentNullException(nameof(options)); | |||||
if (options is MqttClientTcpOptions tcpOptions) | |||||
{ | |||||
var trace = new MqttNetTrace(); | |||||
return new MqttChannelCommunicationAdapter(new MqttTcpChannel(tcpOptions), new MqttPacketSerializer { ProtocolVersion = options.ProtocolVersion }, trace); | |||||
} | |||||
if (options is MqttClientWebSocketOptions webSocketOptions) | |||||
{ | |||||
var trace = new MqttNetTrace(); | |||||
return new MqttChannelCommunicationAdapter(new MqttWebSocketChannel(webSocketOptions), new MqttPacketSerializer { ProtocolVersion = options.ProtocolVersion }, trace); | |||||
} | |||||
throw new NotSupportedException(); | |||||
} | |||||
} | |||||
} |
@@ -7,23 +7,26 @@ using System.Security.Cryptography.X509Certificates; | |||||
using System.Threading; | using System.Threading; | ||||
using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
using MQTTnet.Core.Adapter; | using MQTTnet.Core.Adapter; | ||||
using MQTTnet.Core.Diagnostics; | |||||
using MQTTnet.Core.Serializer; | using MQTTnet.Core.Serializer; | ||||
using MQTTnet.Core.Server; | using MQTTnet.Core.Server; | ||||
using Microsoft.Extensions.Logging; | |||||
using MQTTnet.Core.Client; | |||||
namespace MQTTnet.Implementations | namespace MQTTnet.Implementations | ||||
{ | { | ||||
public class MqttServerAdapter : IMqttServerAdapter, IDisposable | public class MqttServerAdapter : IMqttServerAdapter, IDisposable | ||||
{ | { | ||||
private readonly MqttNetTrace _trace; | |||||
private readonly ILogger<MqttServerAdapter> _logger; | |||||
private readonly IMqttCommunicationAdapterFactory _mqttCommunicationAdapterFactory; | |||||
private CancellationTokenSource _cancellationTokenSource; | private CancellationTokenSource _cancellationTokenSource; | ||||
private Socket _defaultEndpointSocket; | private Socket _defaultEndpointSocket; | ||||
private Socket _tlsEndpointSocket; | private Socket _tlsEndpointSocket; | ||||
private X509Certificate2 _tlsCertificate; | private X509Certificate2 _tlsCertificate; | ||||
public MqttServerAdapter(MqttNetTrace trace) | |||||
public MqttServerAdapter(ILogger<MqttServerAdapter> logger, IMqttCommunicationAdapterFactory mqttCommunicationAdapterFactory) | |||||
{ | { | ||||
_trace = trace ?? throw new ArgumentNullException(nameof(trace)); | |||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger)); | |||||
_mqttCommunicationAdapterFactory = mqttCommunicationAdapterFactory ?? throw new ArgumentNullException(nameof(mqttCommunicationAdapterFactory)); | |||||
} | } | ||||
public event EventHandler<MqttServerAdapterClientAcceptedEventArgs> ClientAccepted; | public event EventHandler<MqttServerAdapterClientAcceptedEventArgs> ClientAccepted; | ||||
@@ -95,17 +98,17 @@ namespace MQTTnet.Implementations | |||||
try | try | ||||
{ | { | ||||
//todo: else branch can be used with min dependency NET46 | //todo: else branch can be used with min dependency NET46 | ||||
#if NET45 | |||||
#if NET451 | |||||
var clientSocket = await Task.Factory.FromAsync(_defaultEndpointSocket.BeginAccept, _defaultEndpointSocket.EndAccept, null).ConfigureAwait(false); | var clientSocket = await Task.Factory.FromAsync(_defaultEndpointSocket.BeginAccept, _defaultEndpointSocket.EndAccept, null).ConfigureAwait(false); | ||||
#else | #else | ||||
var clientSocket = await _defaultEndpointSocket.AcceptAsync().ConfigureAwait(false); | var clientSocket = await _defaultEndpointSocket.AcceptAsync().ConfigureAwait(false); | ||||
#endif | #endif | ||||
var clientAdapter = new MqttChannelCommunicationAdapter(new MqttTcpChannel(clientSocket, null), new MqttPacketSerializer(), _trace); | |||||
var clientAdapter = _mqttCommunicationAdapterFactory.CreateServerMqttCommunicationAdapter(new MqttTcpChannel(clientSocket, null)); | |||||
ClientAccepted?.Invoke(this, new MqttServerAdapterClientAcceptedEventArgs(clientAdapter)); | ClientAccepted?.Invoke(this, new MqttServerAdapterClientAcceptedEventArgs(clientAdapter)); | ||||
} | } | ||||
catch (Exception exception) | catch (Exception exception) | ||||
{ | { | ||||
_trace.Error(nameof(MqttServerAdapter), exception, "Error while accepting connection at default endpoint."); | |||||
_logger.LogError(new EventId(), exception, "Error while accepting connection at default endpoint."); | |||||
//excessive CPU consumed if in endless loop of socket errors | //excessive CPU consumed if in endless loop of socket errors | ||||
await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken).ConfigureAwait(false); | await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken).ConfigureAwait(false); | ||||
@@ -119,7 +122,7 @@ namespace MQTTnet.Implementations | |||||
{ | { | ||||
try | try | ||||
{ | { | ||||
#if NET45 | |||||
#if NET451 | |||||
var clientSocket = await Task.Factory.FromAsync(_tlsEndpointSocket.BeginAccept, _tlsEndpointSocket.EndAccept, null).ConfigureAwait(false); | var clientSocket = await Task.Factory.FromAsync(_tlsEndpointSocket.BeginAccept, _tlsEndpointSocket.EndAccept, null).ConfigureAwait(false); | ||||
#else | #else | ||||
var clientSocket = await _tlsEndpointSocket.AcceptAsync().ConfigureAwait(false); | var clientSocket = await _tlsEndpointSocket.AcceptAsync().ConfigureAwait(false); | ||||
@@ -128,12 +131,12 @@ namespace MQTTnet.Implementations | |||||
var sslStream = new SslStream(new NetworkStream(clientSocket)); | var sslStream = new SslStream(new NetworkStream(clientSocket)); | ||||
await sslStream.AuthenticateAsServerAsync(_tlsCertificate, false, SslProtocols.Tls12, false).ConfigureAwait(false); | await sslStream.AuthenticateAsServerAsync(_tlsCertificate, false, SslProtocols.Tls12, false).ConfigureAwait(false); | ||||
var clientAdapter = new MqttChannelCommunicationAdapter(new MqttTcpChannel(clientSocket, sslStream), new MqttPacketSerializer(), _trace); | |||||
var clientAdapter = _mqttCommunicationAdapterFactory.CreateServerMqttCommunicationAdapter(new MqttTcpChannel(clientSocket, sslStream)); | |||||
ClientAccepted?.Invoke(this, new MqttServerAdapterClientAcceptedEventArgs(clientAdapter)); | ClientAccepted?.Invoke(this, new MqttServerAdapterClientAcceptedEventArgs(clientAdapter)); | ||||
} | } | ||||
catch (Exception exception) | catch (Exception exception) | ||||
{ | { | ||||
_trace.Error(nameof(MqttServerAdapter), exception, "Error while accepting connection at TLS endpoint."); | |||||
_logger.LogError(new EventId(), exception, "Error while accepting connection at TLS endpoint."); | |||||
//excessive CPU consumed if in endless loop of socket errors | //excessive CPU consumed if in endless loop of socket errors | ||||
await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken).ConfigureAwait(false); | await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken).ConfigureAwait(false); | ||||
@@ -59,7 +59,7 @@ namespace MQTTnet.Implementations | |||||
} | } | ||||
//todo: else brach can be used with min dependency NET46 | //todo: else brach can be used with min dependency NET46 | ||||
#if NET45 | |||||
#if NET451 | |||||
await Task.Factory.FromAsync(_socket.BeginConnect, _socket.EndConnect, _options.Server, _options.GetPort(), null).ConfigureAwait(false); | await Task.Factory.FromAsync(_socket.BeginConnect, _socket.EndConnect, _options.Server, _options.GetPort(), null).ConfigureAwait(false); | ||||
#else | #else | ||||
await _socket.ConnectAsync(_options.Server, _options.GetPort()).ConfigureAwait(false); | await _socket.ConnectAsync(_options.Server, _options.GetPort()).ConfigureAwait(false); | ||||
@@ -1,7 +1,7 @@ | |||||
<Project Sdk="Microsoft.NET.Sdk"> | <Project Sdk="Microsoft.NET.Sdk"> | ||||
<PropertyGroup> | <PropertyGroup> | ||||
<TargetFrameworks>netstandard1.3;net45</TargetFrameworks> | |||||
<TargetFrameworks>netstandard1.3;net451</TargetFrameworks> | |||||
<AssemblyName>MQTTnet</AssemblyName> | <AssemblyName>MQTTnet</AssemblyName> | ||||
<RootNamespace>MQTTnet</RootNamespace> | <RootNamespace>MQTTnet</RootNamespace> | ||||
<AssemblyVersion>2.5.0.0</AssemblyVersion> | <AssemblyVersion>2.5.0.0</AssemblyVersion> | ||||
@@ -18,6 +18,11 @@ | |||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" /> | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" /> | ||||
<ItemGroup> | |||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="1.1.1" /> | |||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="1.1.2" /> | |||||
</ItemGroup> | |||||
<ItemGroup> | <ItemGroup> | ||||
<ProjectReference Include="..\..\MQTTnet.Core\MQTTnet.Core.csproj" /> | <ProjectReference Include="..\..\MQTTnet.Core\MQTTnet.Core.csproj" /> | ||||
</ItemGroup> | </ItemGroup> | ||||
@@ -1,20 +0,0 @@ | |||||
using MQTTnet.Core.Client; | |||||
using MQTTnet.Core.Diagnostics; | |||||
using MQTTnet.Core.ManagedClient; | |||||
using MQTTnet.Implementations; | |||||
namespace MQTTnet | |||||
{ | |||||
public class MqttClientFactory : IMqttClientFactory | |||||
{ | |||||
public IMqttClient CreateMqttClient(IMqttNetTraceHandler traceHandler = null) | |||||
{ | |||||
return new MqttClient(new MqttCommunicationAdapterFactory(), new MqttNetTrace(traceHandler)); | |||||
} | |||||
public ManagedMqttClient CreateManagedMqttClient(IMqttNetTraceHandler traceHandler = null) | |||||
{ | |||||
return new ManagedMqttClient(new MqttCommunicationAdapterFactory(), new MqttNetTrace()); | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,104 @@ | |||||
using System; | |||||
using MQTTnet.Core.Adapter; | |||||
using MQTTnet.Core.Client; | |||||
using MQTTnet.Core.Serializer; | |||||
using Microsoft.Extensions.Logging; | |||||
using Microsoft.Extensions.DependencyInjection; | |||||
using MQTTnet.Implementations; | |||||
using MQTTnet.Core.ManagedClient; | |||||
using MQTTnet.Core.Server; | |||||
using System.Linq; | |||||
using MQTTnet.Core.Channel; | |||||
namespace MQTTnet | |||||
{ | |||||
public class MqttFactory : IMqttCommunicationAdapterFactory, IMqttClientSesssionFactory, IMqttClientFactory, IMqttServerFactory | |||||
{ | |||||
private readonly IServiceProvider _serviceProvider; | |||||
private static IServiceProvider BuildServiceProvider() | |||||
{ | |||||
return new ServiceCollection() | |||||
.AddMqttClient() | |||||
.AddMqttServer() | |||||
.AddLogging() | |||||
.BuildServiceProvider(); | |||||
} | |||||
public MqttFactory() | |||||
: this(BuildServiceProvider()) | |||||
{ | |||||
} | |||||
public MqttFactory(IServiceProvider serviceProvider) | |||||
{ | |||||
_serviceProvider = serviceProvider; | |||||
} | |||||
public IMqttCommunicationAdapter CreateClientMqttCommunicationAdapter(IMqttClientOptions options) | |||||
{ | |||||
var logger = _serviceProvider.GetRequiredService<ILogger<MqttChannelCommunicationAdapter>>(); | |||||
return new MqttChannelCommunicationAdapter(CreateMqttCommunicationChannel(options), CreateSerializer(options.ProtocolVersion), logger); | |||||
} | |||||
public IMqttCommunicationAdapter CreateServerMqttCommunicationAdapter(IMqttCommunicationChannel channel) | |||||
{ | |||||
var serializer = _serviceProvider.GetRequiredService<IMqttPacketSerializer>(); | |||||
var logger = _serviceProvider.GetRequiredService<ILogger<MqttChannelCommunicationAdapter>>(); | |||||
return new MqttChannelCommunicationAdapter(channel, serializer, logger); | |||||
} | |||||
public IMqttCommunicationChannel CreateMqttCommunicationChannel(IMqttClientOptions options) | |||||
{ | |||||
if (options == null) throw new ArgumentNullException(nameof(options)); | |||||
switch (options) | |||||
{ | |||||
case MqttClientTcpOptions tcpOptions: | |||||
return CreateTcpChannel(tcpOptions); | |||||
case MqttClientWebSocketOptions webSocketOptions: | |||||
return CreateWebSocketChannel(webSocketOptions); | |||||
default: | |||||
throw new NotSupportedException(); | |||||
} | |||||
} | |||||
public MqttTcpChannel CreateTcpChannel(MqttClientTcpOptions tcpOptions) | |||||
{ | |||||
return new MqttTcpChannel(tcpOptions); | |||||
} | |||||
public MqttWebSocketChannel CreateWebSocketChannel(MqttClientWebSocketOptions webSocketOptions) | |||||
{ | |||||
return new MqttWebSocketChannel(webSocketOptions); | |||||
} | |||||
public MqttPacketSerializer CreateSerializer(MqttProtocolVersion protocolVersion) | |||||
{ | |||||
return new MqttPacketSerializer() | |||||
{ | |||||
ProtocolVersion = protocolVersion | |||||
}; | |||||
} | |||||
public MqttClientSession CreateClientSession(string sessionId, MqttClientSessionsManager mqttClientSessionsManager) | |||||
{ | |||||
return new MqttClientSession(sessionId, mqttClientSessionsManager, _serviceProvider.GetRequiredService<ILogger<MqttClientSession>>(), _serviceProvider.GetRequiredService<ILogger<MqttClientPendingMessagesQueue>>()); | |||||
} | |||||
public IMqttClient CreateMqttClient() | |||||
{ | |||||
return _serviceProvider.GetRequiredService<IMqttClient>(); | |||||
} | |||||
public ManagedMqttClient CreateManagedMqttClient() | |||||
{ | |||||
return _serviceProvider.GetRequiredService<ManagedMqttClient>(); | |||||
} | |||||
public IMqttServer CreateMqttServer() | |||||
{ | |||||
return _serviceProvider.GetRequiredService<IMqttServer>(); | |||||
} | |||||
} | |||||
} |
@@ -1,20 +0,0 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using MQTTnet.Core.Adapter; | |||||
using MQTTnet.Core.Diagnostics; | |||||
using MQTTnet.Core.Server; | |||||
using MQTTnet.Implementations; | |||||
namespace MQTTnet | |||||
{ | |||||
public class MqttServerFactory : IMqttServerFactory | |||||
{ | |||||
public IMqttServer CreateMqttServer(MqttServerOptions options, IMqttNetTraceHandler traceHandler = null) | |||||
{ | |||||
if (options == null) throw new ArgumentNullException(nameof(options)); | |||||
var trace = new MqttNetTrace(traceHandler); | |||||
return new MqttServer(options, new List<IMqttServerAdapter> { new MqttServerAdapter(trace) }, trace); | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,55 @@ | |||||
using Microsoft.Extensions.DependencyInjection; | |||||
using MQTTnet.Core.Adapter; | |||||
using MQTTnet.Core.Client; | |||||
using MQTTnet.Core.ManagedClient; | |||||
using MQTTnet.Core.Serializer; | |||||
using MQTTnet.Core.Server; | |||||
using MQTTnet.Implementations; | |||||
using System; | |||||
namespace MQTTnet | |||||
{ | |||||
public static class ServiceCollectionExtensions | |||||
{ | |||||
public static IServiceCollection AddMqttServer(this IServiceCollection services) | |||||
{ | |||||
services.AddOptions(); | |||||
services.AddSingleton<MqttFactory>(); | |||||
services.AddSingleton<IMqttCommunicationAdapterFactory, MqttFactory>(); | |||||
services.AddSingleton<IMqttClientSesssionFactory, MqttFactory>(); | |||||
services.AddSingleton<IMqttServer,MqttServer>(); | |||||
services.AddSingleton<MqttServer>(); | |||||
services.AddTransient<IMqttServerAdapter, MqttServerAdapter>(); | |||||
services.AddTransient<IMqttPacketSerializer, MqttPacketSerializer>(); | |||||
services.AddTransient<MqttClientSessionsManager>(); | |||||
services.AddTransient<MqttClientRetainedMessagesManager>(); | |||||
return services; | |||||
} | |||||
public static IServiceCollection AddMqttServer(this IServiceCollection services, Action<MqttServerOptions> configureOptions) | |||||
{ | |||||
return services | |||||
.AddMqttServer() | |||||
.Configure(configureOptions); | |||||
} | |||||
public static IServiceCollection AddMqttClient(this IServiceCollection services) | |||||
{ | |||||
services.AddSingleton<MqttFactory>(); | |||||
services.AddSingleton<IMqttCommunicationAdapterFactory, MqttFactory>(); | |||||
services.AddTransient<IMqttClient, MqttClient>(); | |||||
services.AddTransient<MqttClient>(); | |||||
services.AddTransient<IMqttPacketSerializer, MqttPacketSerializer>(); | |||||
services.AddTransient<ManagedMqttClient>(); | |||||
services.AddTransient<MqttPacketDispatcher>(); | |||||
return services; | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,12 @@ | |||||
using MQTTnet.Core.Client; | |||||
using MQTTnet.Core.Channel; | |||||
namespace MQTTnet.Core.Adapter | |||||
{ | |||||
public interface IMqttCommunicationAdapterFactory | |||||
{ | |||||
IMqttCommunicationAdapter CreateClientMqttCommunicationAdapter(IMqttClientOptions options); | |||||
IMqttCommunicationAdapter CreateServerMqttCommunicationAdapter(IMqttCommunicationChannel channel); | |||||
} | |||||
} |
@@ -4,23 +4,23 @@ using System.IO; | |||||
using System.Threading; | using System.Threading; | ||||
using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
using MQTTnet.Core.Channel; | using MQTTnet.Core.Channel; | ||||
using MQTTnet.Core.Diagnostics; | |||||
using MQTTnet.Core.Exceptions; | using MQTTnet.Core.Exceptions; | ||||
using MQTTnet.Core.Internal; | using MQTTnet.Core.Internal; | ||||
using MQTTnet.Core.Packets; | using MQTTnet.Core.Packets; | ||||
using MQTTnet.Core.Serializer; | using MQTTnet.Core.Serializer; | ||||
using Microsoft.Extensions.Logging; | |||||
namespace MQTTnet.Core.Adapter | namespace MQTTnet.Core.Adapter | ||||
{ | { | ||||
public class MqttChannelCommunicationAdapter : IMqttCommunicationAdapter | public class MqttChannelCommunicationAdapter : IMqttCommunicationAdapter | ||||
{ | { | ||||
private readonly MqttNetTrace _trace; | |||||
private readonly ILogger<MqttChannelCommunicationAdapter> _logger; | |||||
private readonly IMqttCommunicationChannel _channel; | private readonly IMqttCommunicationChannel _channel; | ||||
private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1); | private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1); | ||||
public MqttChannelCommunicationAdapter(IMqttCommunicationChannel channel, IMqttPacketSerializer serializer, MqttNetTrace trace) | |||||
public MqttChannelCommunicationAdapter(IMqttCommunicationChannel channel, IMqttPacketSerializer serializer, ILogger<MqttChannelCommunicationAdapter> logger) | |||||
{ | { | ||||
_trace = trace ?? throw new ArgumentNullException(nameof(trace)); | |||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger)); | |||||
_channel = channel ?? throw new ArgumentNullException(nameof(channel)); | _channel = channel ?? throw new ArgumentNullException(nameof(channel)); | ||||
PacketSerializer = serializer ?? throw new ArgumentNullException(nameof(serializer)); | PacketSerializer = serializer ?? throw new ArgumentNullException(nameof(serializer)); | ||||
} | } | ||||
@@ -96,7 +96,7 @@ namespace MQTTnet.Core.Adapter | |||||
continue; | continue; | ||||
} | } | ||||
_trace.Information(nameof(MqttChannelCommunicationAdapter), "TX >>> {0} [Timeout={1}]", packet, timeout); | |||||
_logger.LogInformation("TX >>> {0} [Timeout={1}]", packet, timeout); | |||||
var writeBuffer = PacketSerializer.Serialize(packet); | var writeBuffer = PacketSerializer.Serialize(packet); | ||||
await _channel.SendStream.WriteAsync(writeBuffer, 0, writeBuffer.Length, cancellationToken).ConfigureAwait(false); | await _channel.SendStream.WriteAsync(writeBuffer, 0, writeBuffer.Length, cancellationToken).ConfigureAwait(false); | ||||
@@ -162,7 +162,7 @@ namespace MQTTnet.Core.Adapter | |||||
throw new MqttProtocolViolationException("Received malformed packet."); | throw new MqttProtocolViolationException("Received malformed packet."); | ||||
} | } | ||||
_trace.Information(nameof(MqttChannelCommunicationAdapter), "RX <<< {0}", packet); | |||||
_logger.LogInformation("RX <<< {0}", packet); | |||||
return packet; | return packet; | ||||
} | } | ||||
catch (TaskCanceledException) | catch (TaskCanceledException) | ||||
@@ -1,12 +1,11 @@ | |||||
using MQTTnet.Core.Diagnostics; | |||||
using MQTTnet.Core.ManagedClient; | |||||
using MQTTnet.Core.ManagedClient; | |||||
namespace MQTTnet.Core.Client | namespace MQTTnet.Core.Client | ||||
{ | { | ||||
public interface IMqttClientFactory | public interface IMqttClientFactory | ||||
{ | { | ||||
IMqttClient CreateMqttClient(IMqttNetTraceHandler traceHandler = null); | |||||
IMqttClient CreateMqttClient(); | |||||
ManagedMqttClient CreateManagedMqttClient(IMqttNetTraceHandler traceHandler = null); | |||||
ManagedMqttClient CreateManagedMqttClient(); | |||||
} | } | ||||
} | } |
@@ -1,9 +0,0 @@ | |||||
using MQTTnet.Core.Adapter; | |||||
namespace MQTTnet.Core.Client | |||||
{ | |||||
public interface IMqttCommunicationAdapterFactory | |||||
{ | |||||
IMqttCommunicationAdapter CreateMqttCommunicationAdapter(IMqttClientOptions options); | |||||
} | |||||
} |
@@ -4,11 +4,11 @@ using System.Linq; | |||||
using System.Threading; | using System.Threading; | ||||
using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
using MQTTnet.Core.Adapter; | using MQTTnet.Core.Adapter; | ||||
using MQTTnet.Core.Diagnostics; | |||||
using MQTTnet.Core.Exceptions; | using MQTTnet.Core.Exceptions; | ||||
using MQTTnet.Core.Internal; | using MQTTnet.Core.Internal; | ||||
using MQTTnet.Core.Packets; | using MQTTnet.Core.Packets; | ||||
using MQTTnet.Core.Protocol; | using MQTTnet.Core.Protocol; | ||||
using Microsoft.Extensions.Logging; | |||||
namespace MQTTnet.Core.Client | namespace MQTTnet.Core.Client | ||||
{ | { | ||||
@@ -16,21 +16,21 @@ namespace MQTTnet.Core.Client | |||||
{ | { | ||||
private readonly HashSet<ushort> _unacknowledgedPublishPackets = new HashSet<ushort>(); | private readonly HashSet<ushort> _unacknowledgedPublishPackets = new HashSet<ushort>(); | ||||
private readonly MqttPacketDispatcher _packetDispatcher; | private readonly MqttPacketDispatcher _packetDispatcher; | ||||
private readonly IMqttCommunicationAdapterFactory _communicationChannelFactory; | |||||
private readonly MqttNetTrace _trace; | |||||
private readonly IMqttCommunicationAdapterFactory _communicationAdapterFactory; | |||||
private readonly ILogger<MqttClient> _logger; | |||||
private IMqttClientOptions _options; | private IMqttClientOptions _options; | ||||
private bool _isReceivingPackets; | private bool _isReceivingPackets; | ||||
private int _latestPacketIdentifier; | private int _latestPacketIdentifier; | ||||
private CancellationTokenSource _cancellationTokenSource; | private CancellationTokenSource _cancellationTokenSource; | ||||
private IMqttCommunicationAdapter _adapter; | private IMqttCommunicationAdapter _adapter; | ||||
private IDisposable _scopeHandle; | |||||
public MqttClient(IMqttCommunicationAdapterFactory communicationChannelFactory, MqttNetTrace trace) | |||||
public MqttClient(IMqttCommunicationAdapterFactory communicationAdapterFactory, ILogger<MqttClient> logger, MqttPacketDispatcher packetDispatcher) | |||||
{ | { | ||||
_trace = trace ?? throw new ArgumentNullException(nameof(trace)); | |||||
_communicationChannelFactory = communicationChannelFactory ?? throw new ArgumentNullException(nameof(communicationChannelFactory)); | |||||
_packetDispatcher = new MqttPacketDispatcher(trace); | |||||
_communicationAdapterFactory = communicationAdapterFactory ?? throw new ArgumentNullException(nameof(communicationAdapterFactory)); | |||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger)); | |||||
_packetDispatcher = packetDispatcher ?? throw new ArgumentNullException(nameof(packetDispatcher)); | |||||
} | } | ||||
public event EventHandler<MqttClientConnectedEventArgs> Connected; | public event EventHandler<MqttClientConnectedEventArgs> Connected; | ||||
@@ -52,16 +52,17 @@ namespace MQTTnet.Core.Client | |||||
_latestPacketIdentifier = 0; | _latestPacketIdentifier = 0; | ||||
_packetDispatcher.Reset(); | _packetDispatcher.Reset(); | ||||
_adapter = _communicationChannelFactory.CreateMqttCommunicationAdapter(options); | |||||
_adapter = _communicationAdapterFactory.CreateClientMqttCommunicationAdapter(options); | |||||
_trace.Verbose(nameof(MqttClient), "Trying to connect with server."); | |||||
_scopeHandle = _logger.BeginScope(options.ClientId); | |||||
_logger.LogTrace("Trying to connect with server."); | |||||
await _adapter.ConnectAsync(_options.DefaultCommunicationTimeout).ConfigureAwait(false); | await _adapter.ConnectAsync(_options.DefaultCommunicationTimeout).ConfigureAwait(false); | ||||
_trace.Verbose(nameof(MqttClient), "Connection with server established."); | |||||
_logger.LogTrace("Connection with server established."); | |||||
await SetupIncomingPacketProcessingAsync(); | await SetupIncomingPacketProcessingAsync(); | ||||
var connectResponse = await AuthenticateAsync(options.WillMessage); | var connectResponse = await AuthenticateAsync(options.WillMessage); | ||||
_trace.Verbose(nameof(MqttClient), "MQTT connection with server established."); | |||||
_logger.LogTrace("MQTT connection with server established."); | |||||
if (_options.KeepAlivePeriod != TimeSpan.Zero) | if (_options.KeepAlivePeriod != TimeSpan.Zero) | ||||
{ | { | ||||
@@ -93,6 +94,7 @@ namespace MQTTnet.Core.Client | |||||
finally | finally | ||||
{ | { | ||||
await DisconnectInternalAsync().ConfigureAwait(false); | await DisconnectInternalAsync().ConfigureAwait(false); | ||||
_scopeHandle.Dispose(); | |||||
} | } | ||||
} | } | ||||
@@ -246,11 +248,11 @@ namespace MQTTnet.Core.Client | |||||
try | try | ||||
{ | { | ||||
await _adapter.DisconnectAsync(_options.DefaultCommunicationTimeout).ConfigureAwait(false); | await _adapter.DisconnectAsync(_options.DefaultCommunicationTimeout).ConfigureAwait(false); | ||||
_trace.Information(nameof(MqttClient), "Disconnected from adapter."); | |||||
_logger.LogInformation("Disconnected from adapter."); | |||||
} | } | ||||
catch (Exception exception) | catch (Exception exception) | ||||
{ | { | ||||
_trace.Warning(nameof(MqttClient), exception, "Error while disconnecting from adapter."); | |||||
_logger.LogWarning(new EventId(), exception, "Error while disconnecting from adapter."); | |||||
} | } | ||||
finally | finally | ||||
{ | { | ||||
@@ -262,7 +264,7 @@ namespace MQTTnet.Core.Client | |||||
{ | { | ||||
try | try | ||||
{ | { | ||||
_trace.Information(nameof(MqttClient), "Received <<< {0}", packet); | |||||
_logger.LogInformation("Received <<< {0}", packet); | |||||
if (packet is MqttPingReqPacket) | if (packet is MqttPingReqPacket) | ||||
{ | { | ||||
@@ -292,7 +294,7 @@ namespace MQTTnet.Core.Client | |||||
} | } | ||||
catch (Exception exception) | catch (Exception exception) | ||||
{ | { | ||||
_trace.Error(nameof(MqttClient), exception, "Unhandled exception while processing received packet."); | |||||
_logger.LogError(new EventId(), exception, "Unhandled exception while processing received packet."); | |||||
} | } | ||||
} | } | ||||
@@ -305,7 +307,7 @@ namespace MQTTnet.Core.Client | |||||
} | } | ||||
catch (Exception exception) | catch (Exception exception) | ||||
{ | { | ||||
_trace.Error(nameof(MqttClient), exception, "Unhandled exception while handling application message."); | |||||
_logger.LogError(new EventId(), exception, "Unhandled exception while handling application message."); | |||||
} | } | ||||
} | } | ||||
@@ -369,7 +371,7 @@ namespace MQTTnet.Core.Client | |||||
private async Task SendKeepAliveMessagesAsync(CancellationToken cancellationToken) | private async Task SendKeepAliveMessagesAsync(CancellationToken cancellationToken) | ||||
{ | { | ||||
_trace.Information(nameof(MqttClient), "Start sending keep alive packets."); | |||||
_logger.LogInformation("Start sending keep alive packets."); | |||||
try | try | ||||
{ | { | ||||
@@ -394,23 +396,23 @@ namespace MQTTnet.Core.Client | |||||
return; | return; | ||||
} | } | ||||
_trace.Warning(nameof(MqttClient), exception, "MQTT communication exception while sending/receiving keep alive packets."); | |||||
_logger.LogWarning(new EventId(), exception, "MQTT communication exception while sending/receiving keep alive packets."); | |||||
await DisconnectInternalAsync().ConfigureAwait(false); | await DisconnectInternalAsync().ConfigureAwait(false); | ||||
} | } | ||||
catch (Exception exception) | catch (Exception exception) | ||||
{ | { | ||||
_trace.Warning(nameof(MqttClient), exception, "Unhandled exception while sending/receiving keep alive packets."); | |||||
_logger.LogWarning(new EventId(), exception, "Unhandled exception while sending/receiving keep alive packets."); | |||||
await DisconnectInternalAsync().ConfigureAwait(false); | await DisconnectInternalAsync().ConfigureAwait(false); | ||||
} | } | ||||
finally | finally | ||||
{ | { | ||||
_trace.Information(nameof(MqttClient), "Stopped sending keep alive packets."); | |||||
_logger.LogInformation("Stopped sending keep alive packets."); | |||||
} | } | ||||
} | } | ||||
private async Task ReceivePackets(CancellationToken cancellationToken) | private async Task ReceivePackets(CancellationToken cancellationToken) | ||||
{ | { | ||||
_trace.Information(nameof(MqttClient), "Start receiving packets."); | |||||
_logger.LogInformation("Start receiving packets."); | |||||
try | try | ||||
{ | { | ||||
@@ -437,17 +439,17 @@ namespace MQTTnet.Core.Client | |||||
return; | return; | ||||
} | } | ||||
_trace.Warning(nameof(MqttClient), exception, "MQTT communication exception while receiving packets."); | |||||
_logger.LogWarning(new EventId(), exception, "MQTT communication exception while receiving packets."); | |||||
await DisconnectInternalAsync().ConfigureAwait(false); | await DisconnectInternalAsync().ConfigureAwait(false); | ||||
} | } | ||||
catch (Exception exception) | catch (Exception exception) | ||||
{ | { | ||||
_trace.Error(nameof(MqttClient), exception, "Unhandled exception while receiving packets."); | |||||
_logger.LogError(new EventId(), exception, "Unhandled exception while receiving packets."); | |||||
await DisconnectInternalAsync().ConfigureAwait(false); | await DisconnectInternalAsync().ConfigureAwait(false); | ||||
} | } | ||||
finally | finally | ||||
{ | { | ||||
_trace.Information(nameof(MqttClient), "Stopped receiving packets."); | |||||
_logger.LogInformation(nameof(MqttClient), "Stopped receiving packets."); | |||||
} | } | ||||
} | } | ||||
@@ -1,10 +1,10 @@ | |||||
using System; | using System; | ||||
using System.Collections.Concurrent; | |||||
using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
using MQTTnet.Core.Diagnostics; | |||||
using MQTTnet.Core.Exceptions; | using MQTTnet.Core.Exceptions; | ||||
using MQTTnet.Core.Internal; | using MQTTnet.Core.Internal; | ||||
using MQTTnet.Core.Packets; | using MQTTnet.Core.Packets; | ||||
using System.Collections.Concurrent; | |||||
using Microsoft.Extensions.Logging; | |||||
namespace MQTTnet.Core.Client | namespace MQTTnet.Core.Client | ||||
{ | { | ||||
@@ -12,11 +12,11 @@ namespace MQTTnet.Core.Client | |||||
{ | { | ||||
private readonly ConcurrentDictionary<Type, TaskCompletionSource<MqttBasePacket>> _packetByResponseType = new ConcurrentDictionary<Type, TaskCompletionSource<MqttBasePacket>>(); | private readonly ConcurrentDictionary<Type, TaskCompletionSource<MqttBasePacket>> _packetByResponseType = new ConcurrentDictionary<Type, TaskCompletionSource<MqttBasePacket>>(); | ||||
private readonly ConcurrentDictionary<Type, ConcurrentDictionary<ushort, TaskCompletionSource<MqttBasePacket>>> _packetByResponseTypeAndIdentifier = new ConcurrentDictionary<Type, ConcurrentDictionary<ushort, TaskCompletionSource<MqttBasePacket>>>(); | private readonly ConcurrentDictionary<Type, ConcurrentDictionary<ushort, TaskCompletionSource<MqttBasePacket>>> _packetByResponseTypeAndIdentifier = new ConcurrentDictionary<Type, ConcurrentDictionary<ushort, TaskCompletionSource<MqttBasePacket>>>(); | ||||
private readonly MqttNetTrace _trace; | |||||
private readonly ILogger<MqttPacketDispatcher> _logger; | |||||
public MqttPacketDispatcher(MqttNetTrace trace) | |||||
public MqttPacketDispatcher(ILogger<MqttPacketDispatcher> logger) | |||||
{ | { | ||||
_trace = trace ?? throw new ArgumentNullException(nameof(trace)); | |||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger)); | |||||
} | } | ||||
public async Task<MqttBasePacket> WaitForPacketAsync(MqttBasePacket request, Type responseType, TimeSpan timeout) | public async Task<MqttBasePacket> WaitForPacketAsync(MqttBasePacket request, Type responseType, TimeSpan timeout) | ||||
@@ -30,7 +30,7 @@ namespace MQTTnet.Core.Client | |||||
} | } | ||||
catch (MqttCommunicationTimedOutException) | catch (MqttCommunicationTimedOutException) | ||||
{ | { | ||||
_trace.Warning(nameof(MqttPacketDispatcher), "Timeout while waiting for packet of type '{0}'.", responseType.Name); | |||||
_logger.LogWarning("Timeout while waiting for packet of type '{0}'.", responseType.Name); | |||||
throw; | throw; | ||||
} | } | ||||
finally | finally | ||||
@@ -1,9 +0,0 @@ | |||||
namespace MQTTnet.Core.Diagnostics | |||||
{ | |||||
public interface IMqttNetTraceHandler | |||||
{ | |||||
bool IsEnabled { get; } | |||||
void HandleTraceMessage(MqttNetTraceMessage traceMessage); | |||||
} | |||||
} |
@@ -1,77 +0,0 @@ | |||||
using System; | |||||
namespace MQTTnet.Core.Diagnostics | |||||
{ | |||||
public sealed class MqttNetTrace : IMqttNetTraceHandler | |||||
{ | |||||
private readonly IMqttNetTraceHandler _traceHandler; | |||||
public MqttNetTrace(IMqttNetTraceHandler customTraceHandler = null) | |||||
{ | |||||
_traceHandler = customTraceHandler ?? this; | |||||
} | |||||
public static event EventHandler<MqttNetTraceMessagePublishedEventArgs> TraceMessagePublished; | |||||
public bool IsEnabled => TraceMessagePublished != null; | |||||
public void Verbose(string source, string message, params object[] parameters) | |||||
{ | |||||
Publish(source, MqttNetTraceLevel.Verbose, null, message, parameters); | |||||
} | |||||
public void Information(string source, string message, params object[] parameters) | |||||
{ | |||||
Publish(source, MqttNetTraceLevel.Information, null, message, parameters); | |||||
} | |||||
public void Warning(string source, string message, params object[] parameters) | |||||
{ | |||||
Publish(source, MqttNetTraceLevel.Warning, null, message, parameters); | |||||
} | |||||
public void Warning(string source, Exception exception, string message, params object[] parameters) | |||||
{ | |||||
Publish(source, MqttNetTraceLevel.Warning, exception, message, parameters); | |||||
} | |||||
public void Error(string source, string message, params object[] parameters) | |||||
{ | |||||
Publish(source, MqttNetTraceLevel.Error, null, message, parameters); | |||||
} | |||||
public void Error(string source, Exception exception, string message, params object[] parameters) | |||||
{ | |||||
Publish(source, MqttNetTraceLevel.Error, exception, message, parameters); | |||||
} | |||||
public void HandleTraceMessage(MqttNetTraceMessage mqttNetTraceMessage) | |||||
{ | |||||
TraceMessagePublished?.Invoke(this, new MqttNetTraceMessagePublishedEventArgs(mqttNetTraceMessage)); | |||||
} | |||||
private void Publish(string source, MqttNetTraceLevel traceLevel, Exception exception, string message, params object[] parameters) | |||||
{ | |||||
if (!_traceHandler.IsEnabled) | |||||
{ | |||||
return; | |||||
} | |||||
var now = DateTime.Now; | |||||
if (parameters?.Length > 0) | |||||
{ | |||||
try | |||||
{ | |||||
message = string.Format(message, parameters); | |||||
} | |||||
catch (Exception formatException) | |||||
{ | |||||
Error(nameof(MqttNetTrace), formatException, "Error while tracing message: " + message); | |||||
return; | |||||
} | |||||
} | |||||
_traceHandler.HandleTraceMessage(new MqttNetTraceMessage(now, Environment.CurrentManagedThreadId, source, traceLevel, message, exception)); | |||||
} | |||||
} | |||||
} |
@@ -1,10 +0,0 @@ | |||||
namespace MQTTnet.Core.Diagnostics | |||||
{ | |||||
public enum MqttNetTraceLevel | |||||
{ | |||||
Verbose, | |||||
Information, | |||||
Warning, | |||||
Error | |||||
} | |||||
} |
@@ -1,29 +0,0 @@ | |||||
using System; | |||||
namespace MQTTnet.Core.Diagnostics | |||||
{ | |||||
public sealed class MqttNetTraceMessage | |||||
{ | |||||
public MqttNetTraceMessage(DateTime timestamp, int threadId, string source, MqttNetTraceLevel level, string message, Exception exception) | |||||
{ | |||||
Timestamp = timestamp; | |||||
ThreadId = threadId; | |||||
Source = source; | |||||
Level = level; | |||||
Message = message; | |||||
Exception = exception; | |||||
} | |||||
public DateTime Timestamp { get; } | |||||
public int ThreadId { get; } | |||||
public string Source { get; } | |||||
public MqttNetTraceLevel Level { get; } | |||||
public string Message { get; } | |||||
public Exception Exception { get; } | |||||
} | |||||
} |
@@ -1,14 +0,0 @@ | |||||
using System; | |||||
namespace MQTTnet.Core.Diagnostics | |||||
{ | |||||
public sealed class MqttNetTraceMessagePublishedEventArgs : EventArgs | |||||
{ | |||||
public MqttNetTraceMessagePublishedEventArgs(MqttNetTraceMessage traceMessage) | |||||
{ | |||||
TraceMessage = traceMessage ?? throw new ArgumentNullException(nameof(traceMessage)); | |||||
} | |||||
public MqttNetTraceMessage TraceMessage { get; } | |||||
} | |||||
} |
@@ -22,4 +22,9 @@ | |||||
<PackageLicenseUrl></PackageLicenseUrl> | <PackageLicenseUrl></PackageLicenseUrl> | ||||
</PropertyGroup> | </PropertyGroup> | ||||
<ItemGroup> | |||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="1.1.2" /> | |||||
<PackageReference Include="Microsoft.Extensions.Options" Version="1.1.2" /> | |||||
</ItemGroup> | |||||
</Project> | </Project> |
@@ -5,10 +5,10 @@ using System.Linq; | |||||
using System.Threading; | using System.Threading; | ||||
using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
using MQTTnet.Core.Client; | using MQTTnet.Core.Client; | ||||
using MQTTnet.Core.Diagnostics; | |||||
using MQTTnet.Core.Exceptions; | using MQTTnet.Core.Exceptions; | ||||
using MQTTnet.Core.Packets; | using MQTTnet.Core.Packets; | ||||
using MQTTnet.Core.Protocol; | using MQTTnet.Core.Protocol; | ||||
using Microsoft.Extensions.Logging; | |||||
namespace MQTTnet.Core.ManagedClient | namespace MQTTnet.Core.ManagedClient | ||||
{ | { | ||||
@@ -19,7 +19,7 @@ namespace MQTTnet.Core.ManagedClient | |||||
private readonly HashSet<TopicFilter> _subscriptions = new HashSet<TopicFilter>(); | private readonly HashSet<TopicFilter> _subscriptions = new HashSet<TopicFilter>(); | ||||
private readonly IMqttClient _mqttClient; | private readonly IMqttClient _mqttClient; | ||||
private readonly MqttNetTrace _trace; | |||||
private readonly ILogger<ManagedMqttClient> _logger; | |||||
private CancellationTokenSource _connectionCancellationToken; | private CancellationTokenSource _connectionCancellationToken; | ||||
private CancellationTokenSource _publishingCancellationToken; | private CancellationTokenSource _publishingCancellationToken; | ||||
@@ -27,12 +27,11 @@ namespace MQTTnet.Core.ManagedClient | |||||
private IManagedMqttClientOptions _options; | private IManagedMqttClientOptions _options; | ||||
private bool _subscriptionsNotPushed; | private bool _subscriptionsNotPushed; | ||||
public ManagedMqttClient(IMqttCommunicationAdapterFactory communicationChannelFactory, MqttNetTrace trace) | |||||
public ManagedMqttClient(ILogger<ManagedMqttClient> logger, IMqttClient mqttClient) | |||||
{ | { | ||||
if (communicationChannelFactory == null) throw new ArgumentNullException(nameof(communicationChannelFactory)); | |||||
_trace = trace ?? throw new ArgumentNullException(nameof(trace)); | |||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger)); | |||||
_mqttClient = mqttClient ?? throw new ArgumentNullException(nameof(mqttClient)); | |||||
_mqttClient = new MqttClient(communicationChannelFactory, _trace); | |||||
_mqttClient.Connected += OnConnected; | _mqttClient.Connected += OnConnected; | ||||
_mqttClient.Disconnected += OnDisconnected; | _mqttClient.Disconnected += OnDisconnected; | ||||
_mqttClient.ApplicationMessageReceived += OnApplicationMessageReceived; | _mqttClient.ApplicationMessageReceived += OnApplicationMessageReceived; | ||||
@@ -77,7 +76,7 @@ namespace MQTTnet.Core.ManagedClient | |||||
Task.Factory.StartNew(() => MaintainConnectionAsync(_connectionCancellationToken.Token), _connectionCancellationToken.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default).ConfigureAwait(false); | Task.Factory.StartNew(() => MaintainConnectionAsync(_connectionCancellationToken.Token), _connectionCancellationToken.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default).ConfigureAwait(false); | ||||
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed | #pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed | ||||
_trace.Information(nameof(ManagedMqttClient), "Started"); | |||||
_logger.LogInformation("Started"); | |||||
} | } | ||||
public Task StopAsync() | public Task StopAsync() | ||||
@@ -179,16 +178,16 @@ namespace MQTTnet.Core.ManagedClient | |||||
} | } | ||||
catch (MqttCommunicationException exception) | catch (MqttCommunicationException exception) | ||||
{ | { | ||||
_trace.Warning(nameof(ManagedMqttClient), exception, "Communication exception while maintaining connection."); | |||||
_logger.LogWarning(new EventId(), exception, "Communication exception while maintaining connection."); | |||||
} | } | ||||
catch (Exception exception) | catch (Exception exception) | ||||
{ | { | ||||
_trace.Error(nameof(ManagedMqttClient), exception, "Unhandled exception while maintaining connection."); | |||||
_logger.LogError(new EventId(), exception, "Unhandled exception while maintaining connection."); | |||||
} | } | ||||
finally | finally | ||||
{ | { | ||||
await _mqttClient.DisconnectAsync().ConfigureAwait(false); | await _mqttClient.DisconnectAsync().ConfigureAwait(false); | ||||
_trace.Information(nameof(ManagedMqttClient), "Stopped"); | |||||
_logger.LogInformation("Stopped"); | |||||
} | } | ||||
} | } | ||||
@@ -217,7 +216,7 @@ namespace MQTTnet.Core.ManagedClient | |||||
} | } | ||||
finally | finally | ||||
{ | { | ||||
_trace.Information(nameof(ManagedMqttClient), "Stopped publishing messages"); | |||||
_logger.LogInformation("Stopped publishing messages"); | |||||
} | } | ||||
} | } | ||||
@@ -229,7 +228,7 @@ namespace MQTTnet.Core.ManagedClient | |||||
} | } | ||||
catch (MqttCommunicationException exception) | catch (MqttCommunicationException exception) | ||||
{ | { | ||||
_trace.Warning(nameof(ManagedMqttClient), exception, "Publishing application message failed."); | |||||
_logger.LogWarning(new EventId(), exception, "Publishing application message failed."); | |||||
if (message.QualityOfServiceLevel > MqttQualityOfServiceLevel.AtMostOnce) | if (message.QualityOfServiceLevel > MqttQualityOfServiceLevel.AtMostOnce) | ||||
{ | { | ||||
@@ -238,13 +237,13 @@ namespace MQTTnet.Core.ManagedClient | |||||
} | } | ||||
catch (Exception exception) | catch (Exception exception) | ||||
{ | { | ||||
_trace.Error(nameof(ManagedMqttClient), exception, "Unhandled exception while publishing queued application message."); | |||||
_logger.LogError(new EventId(), exception, "Unhandled exception while publishing queued application message."); | |||||
} | } | ||||
} | } | ||||
private async Task PushSubscriptionsAsync() | private async Task PushSubscriptionsAsync() | ||||
{ | { | ||||
_trace.Information(nameof(ManagedMqttClient), "Synchronizing subscriptions"); | |||||
_logger.LogInformation(nameof(ManagedMqttClient), "Synchronizing subscriptions"); | |||||
List<TopicFilter> subscriptions; | List<TopicFilter> subscriptions; | ||||
lock (_subscriptions) | lock (_subscriptions) | ||||
@@ -264,7 +263,7 @@ namespace MQTTnet.Core.ManagedClient | |||||
} | } | ||||
catch (Exception exception) | catch (Exception exception) | ||||
{ | { | ||||
_trace.Warning(nameof(ManagedMqttClient), exception, "Synchronizing subscriptions failed"); | |||||
_logger.LogWarning(new EventId(), exception, "Synchronizing subscriptions failed"); | |||||
_subscriptionsNotPushed = true; | _subscriptionsNotPushed = true; | ||||
} | } | ||||
} | } | ||||
@@ -0,0 +1,7 @@ | |||||
namespace MQTTnet.Core.Server | |||||
{ | |||||
public interface IMqttClientSesssionFactory | |||||
{ | |||||
MqttClientSession CreateClientSession(string sessionId, MqttClientSessionsManager mqttClientSessionsManager); | |||||
} | |||||
} |
@@ -1,9 +1,7 @@ | |||||
using MQTTnet.Core.Diagnostics; | |||||
namespace MQTTnet.Core.Server | |||||
namespace MQTTnet.Core.Server | |||||
{ | { | ||||
public interface IMqttServerFactory | public interface IMqttServerFactory | ||||
{ | { | ||||
IMqttServer CreateMqttServer(MqttServerOptions options, IMqttNetTraceHandler traceHandler = null); | |||||
IMqttServer CreateMqttServer(); | |||||
} | } | ||||
} | } |
@@ -3,10 +3,10 @@ using System.Collections.Concurrent; | |||||
using System.Threading; | using System.Threading; | ||||
using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
using MQTTnet.Core.Adapter; | using MQTTnet.Core.Adapter; | ||||
using MQTTnet.Core.Diagnostics; | |||||
using MQTTnet.Core.Exceptions; | using MQTTnet.Core.Exceptions; | ||||
using MQTTnet.Core.Packets; | using MQTTnet.Core.Packets; | ||||
using MQTTnet.Core.Protocol; | using MQTTnet.Core.Protocol; | ||||
using Microsoft.Extensions.Logging; | |||||
namespace MQTTnet.Core.Server | namespace MQTTnet.Core.Server | ||||
{ | { | ||||
@@ -15,11 +15,11 @@ namespace MQTTnet.Core.Server | |||||
private readonly BlockingCollection<MqttPublishPacket> _pendingPublishPackets = new BlockingCollection<MqttPublishPacket>(); | private readonly BlockingCollection<MqttPublishPacket> _pendingPublishPackets = new BlockingCollection<MqttPublishPacket>(); | ||||
private readonly MqttClientSession _session; | private readonly MqttClientSession _session; | ||||
private readonly MqttServerOptions _options; | private readonly MqttServerOptions _options; | ||||
private readonly MqttNetTrace _trace; | |||||
private readonly ILogger<MqttClientPendingMessagesQueue> _logger; | |||||
public MqttClientPendingMessagesQueue(MqttServerOptions options, MqttClientSession session, MqttNetTrace trace) | |||||
public MqttClientPendingMessagesQueue(MqttServerOptions options, MqttClientSession session, ILogger<MqttClientPendingMessagesQueue> logger) | |||||
{ | { | ||||
_trace = trace ?? throw new ArgumentNullException(nameof(trace)); | |||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger)); | |||||
_session = session ?? throw new ArgumentNullException(nameof(session)); | _session = session ?? throw new ArgumentNullException(nameof(session)); | ||||
_options = options ?? throw new ArgumentNullException(nameof(options)); | _options = options ?? throw new ArgumentNullException(nameof(options)); | ||||
} | } | ||||
@@ -52,7 +52,7 @@ namespace MQTTnet.Core.Server | |||||
} | } | ||||
catch (Exception exception) | catch (Exception exception) | ||||
{ | { | ||||
_trace.Error(nameof(MqttClientPendingMessagesQueue), exception, "Unhandled exception while sending pending publish packets."); | |||||
_logger.LogError(new EventId(), exception, "Unhandled exception while sending pending publish packets."); | |||||
} | } | ||||
} | } | ||||
@@ -68,18 +68,18 @@ namespace MQTTnet.Core.Server | |||||
{ | { | ||||
if (exception is MqttCommunicationTimedOutException) | if (exception is MqttCommunicationTimedOutException) | ||||
{ | { | ||||
_trace.Warning(nameof(MqttClientPendingMessagesQueue), exception, "Sending publish packet failed due to timeout."); | |||||
_logger.LogWarning(new EventId(), exception, "Sending publish packet failed due to timeout."); | |||||
} | } | ||||
else if (exception is MqttCommunicationException) | else if (exception is MqttCommunicationException) | ||||
{ | { | ||||
_trace.Warning(nameof(MqttClientPendingMessagesQueue), exception, "Sending publish packet failed due to communication exception."); | |||||
_logger.LogWarning(new EventId(), exception, "Sending publish packet failed due to communication exception."); | |||||
} | } | ||||
if (exception is OperationCanceledException) | if (exception is OperationCanceledException) | ||||
{ | { | ||||
} | } | ||||
else | else | ||||
{ | { | ||||
_trace.Error(nameof(MqttClientPendingMessagesQueue), exception, "Sending publish packet failed."); | |||||
_logger.LogError(new EventId(), exception, "Sending publish packet failed."); | |||||
} | } | ||||
if (packet.QualityOfServiceLevel > MqttQualityOfServiceLevel.AtMostOnce) | if (packet.QualityOfServiceLevel > MqttQualityOfServiceLevel.AtMostOnce) | ||||
@@ -2,21 +2,22 @@ | |||||
using System.Collections.Generic; | using System.Collections.Generic; | ||||
using System.Linq; | using System.Linq; | ||||
using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
using MQTTnet.Core.Diagnostics; | |||||
using MQTTnet.Core.Packets; | using MQTTnet.Core.Packets; | ||||
using Microsoft.Extensions.Logging; | |||||
using Microsoft.Extensions.Options; | |||||
namespace MQTTnet.Core.Server | namespace MQTTnet.Core.Server | ||||
{ | { | ||||
public sealed class MqttClientRetainedMessagesManager | public sealed class MqttClientRetainedMessagesManager | ||||
{ | { | ||||
private readonly Dictionary<string, MqttApplicationMessage> _retainedMessages = new Dictionary<string, MqttApplicationMessage>(); | private readonly Dictionary<string, MqttApplicationMessage> _retainedMessages = new Dictionary<string, MqttApplicationMessage>(); | ||||
private readonly MqttNetTrace _trace; | |||||
private readonly ILogger<MqttClientRetainedMessagesManager> _logger; | |||||
private readonly MqttServerOptions _options; | private readonly MqttServerOptions _options; | ||||
public MqttClientRetainedMessagesManager(MqttServerOptions options, MqttNetTrace trace) | |||||
public MqttClientRetainedMessagesManager(IOptions<MqttServerOptions> options, ILogger<MqttClientRetainedMessagesManager> logger) | |||||
{ | { | ||||
_trace = trace ?? throw new ArgumentNullException(nameof(trace)); | |||||
_options = options ?? throw new ArgumentNullException(nameof(options)); | |||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger)); | |||||
_options = options.Value ?? throw new ArgumentNullException(nameof(options)); | |||||
} | } | ||||
public async Task LoadMessagesAsync() | public async Task LoadMessagesAsync() | ||||
@@ -40,7 +41,7 @@ namespace MQTTnet.Core.Server | |||||
} | } | ||||
catch (Exception exception) | catch (Exception exception) | ||||
{ | { | ||||
_trace.Error(nameof(MqttClientRetainedMessagesManager), exception, "Unhandled exception while loading retained messages."); | |||||
_logger.LogError(new EventId(), exception, "Unhandled exception while loading retained messages."); | |||||
} | } | ||||
} | } | ||||
@@ -54,12 +55,12 @@ namespace MQTTnet.Core.Server | |||||
if (applicationMessage.Payload?.Any() == false) | if (applicationMessage.Payload?.Any() == false) | ||||
{ | { | ||||
_retainedMessages.Remove(applicationMessage.Topic); | _retainedMessages.Remove(applicationMessage.Topic); | ||||
_trace.Information(nameof(MqttClientRetainedMessagesManager), "Client '{0}' cleared retained message for topic '{1}'.", clientId, applicationMessage.Topic); | |||||
_logger.LogInformation("Client '{0}' cleared retained message for topic '{1}'.", clientId, applicationMessage.Topic); | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
_retainedMessages[applicationMessage.Topic] = applicationMessage; | _retainedMessages[applicationMessage.Topic] = applicationMessage; | ||||
_trace.Information(nameof(MqttClientRetainedMessagesManager), "Client '{0}' updated retained message for topic '{1}'.", clientId, applicationMessage.Topic); | |||||
_logger.LogInformation("Client '{0}' updated retained message for topic '{1}'.", clientId, applicationMessage.Topic); | |||||
} | } | ||||
allRetainedMessages = new List<MqttApplicationMessage>(_retainedMessages.Values); | allRetainedMessages = new List<MqttApplicationMessage>(_retainedMessages.Values); | ||||
@@ -75,7 +76,7 @@ namespace MQTTnet.Core.Server | |||||
} | } | ||||
catch (Exception exception) | catch (Exception exception) | ||||
{ | { | ||||
_trace.Error(nameof(MqttClientRetainedMessagesManager), exception, "Unhandled exception while saving retained messages."); | |||||
_logger.LogError(new EventId(), exception, "Unhandled exception while saving retained messages."); | |||||
} | } | ||||
} | } | ||||
@@ -3,12 +3,12 @@ using System.Collections.Generic; | |||||
using System.Threading; | using System.Threading; | ||||
using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
using MQTTnet.Core.Adapter; | using MQTTnet.Core.Adapter; | ||||
using MQTTnet.Core.Diagnostics; | |||||
using MQTTnet.Core.Exceptions; | using MQTTnet.Core.Exceptions; | ||||
using MQTTnet.Core.Internal; | using MQTTnet.Core.Internal; | ||||
using MQTTnet.Core.Packets; | using MQTTnet.Core.Packets; | ||||
using MQTTnet.Core.Protocol; | using MQTTnet.Core.Protocol; | ||||
using MQTTnet.Core.Serializer; | using MQTTnet.Core.Serializer; | ||||
using Microsoft.Extensions.Logging; | |||||
namespace MQTTnet.Core.Server | namespace MQTTnet.Core.Server | ||||
{ | { | ||||
@@ -20,19 +20,20 @@ namespace MQTTnet.Core.Server | |||||
private readonly MqttClientSessionsManager _mqttClientSessionsManager; | private readonly MqttClientSessionsManager _mqttClientSessionsManager; | ||||
private readonly MqttClientPendingMessagesQueue _pendingMessagesQueue; | private readonly MqttClientPendingMessagesQueue _pendingMessagesQueue; | ||||
private readonly MqttServerOptions _options; | private readonly MqttServerOptions _options; | ||||
private readonly MqttNetTrace _trace; | |||||
private readonly ILogger<MqttClientSession> _logger; | |||||
private IMqttCommunicationAdapter _adapter; | private IMqttCommunicationAdapter _adapter; | ||||
private CancellationTokenSource _cancellationTokenSource; | private CancellationTokenSource _cancellationTokenSource; | ||||
private MqttApplicationMessage _willMessage; | private MqttApplicationMessage _willMessage; | ||||
public MqttClientSession(string clientId, MqttServerOptions options, MqttClientSessionsManager mqttClientSessionsManager, MqttNetTrace trace) | |||||
public MqttClientSession(string clientId, MqttClientSessionsManager mqttClientSessionsManager, ILogger<MqttClientSession> logger, ILogger<MqttClientPendingMessagesQueue> msgQueueLogger) | |||||
{ | { | ||||
_trace = trace ?? throw new ArgumentNullException(nameof(trace)); | |||||
ClientId = clientId; | ClientId = clientId; | ||||
_options = options ?? throw new ArgumentNullException(nameof(options)); | |||||
_options = mqttClientSessionsManager.Options; | |||||
_mqttClientSessionsManager = mqttClientSessionsManager ?? throw new ArgumentNullException(nameof(mqttClientSessionsManager)); | _mqttClientSessionsManager = mqttClientSessionsManager ?? throw new ArgumentNullException(nameof(mqttClientSessionsManager)); | ||||
_pendingMessagesQueue = new MqttClientPendingMessagesQueue(options, this, trace); | |||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger)); | |||||
_pendingMessagesQueue = new MqttClientPendingMessagesQueue(mqttClientSessionsManager.Options, this, msgQueueLogger); | |||||
} | } | ||||
public string ClientId { get; } | public string ClientId { get; } | ||||
@@ -60,11 +61,11 @@ namespace MQTTnet.Core.Server | |||||
} | } | ||||
catch (MqttCommunicationException exception) | catch (MqttCommunicationException exception) | ||||
{ | { | ||||
_trace.Warning(nameof(MqttClientSession), exception, "Client '{0}': Communication exception while processing client packets.", ClientId); | |||||
_logger.LogWarning(new EventId(), exception, "Client '{0}': Communication exception while processing client packets.", ClientId); | |||||
} | } | ||||
catch (Exception exception) | catch (Exception exception) | ||||
{ | { | ||||
_trace.Error(nameof(MqttClientSession), exception, "Client '{0}': Unhandled exception while processing client packets.", ClientId); | |||||
_logger.LogError(new EventId(), exception, "Client '{0}': Unhandled exception while processing client packets.", ClientId); | |||||
} | } | ||||
} | } | ||||
@@ -81,7 +82,7 @@ namespace MQTTnet.Core.Server | |||||
_adapter = null; | _adapter = null; | ||||
_trace.Information(nameof(MqttClientSession), "Client '{0}': Disconnected.", ClientId); | |||||
_logger.LogInformation("Client '{0}': Disconnected.", ClientId); | |||||
} | } | ||||
public void EnqueuePublishPacket(MqttPublishPacket publishPacket) | public void EnqueuePublishPacket(MqttPublishPacket publishPacket) | ||||
@@ -94,7 +95,7 @@ namespace MQTTnet.Core.Server | |||||
} | } | ||||
_pendingMessagesQueue.Enqueue(publishPacket); | _pendingMessagesQueue.Enqueue(publishPacket); | ||||
_trace.Verbose(nameof(MqttClientSession), "Client '{0}': Enqueued pending publish packet.", ClientId); | |||||
_logger.LogTrace("Client '{0}': Enqueued pending publish packet.", ClientId); | |||||
} | } | ||||
public void Dispose() | public void Dispose() | ||||
@@ -118,12 +119,12 @@ namespace MQTTnet.Core.Server | |||||
} | } | ||||
catch (MqttCommunicationException exception) | catch (MqttCommunicationException exception) | ||||
{ | { | ||||
_trace.Warning(nameof(MqttClientSession), exception, "Client '{0}': Communication exception while processing client packets.", ClientId); | |||||
_logger.LogWarning(new EventId(), exception, "Client '{0}': Communication exception while processing client packets.", ClientId); | |||||
Stop(); | Stop(); | ||||
} | } | ||||
catch (Exception exception) | catch (Exception exception) | ||||
{ | { | ||||
_trace.Error(nameof(MqttClientSession), exception, "Client '{0}': Unhandled exception while processing client packets.", ClientId); | |||||
_logger.LogError(new EventId(), exception, "Client '{0}': Unhandled exception while processing client packets.", ClientId); | |||||
Stop(); | Stop(); | ||||
} | } | ||||
} | } | ||||
@@ -165,7 +166,7 @@ namespace MQTTnet.Core.Server | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
_trace.Warning(nameof(MqttClientSession), "Client '{0}': Received not supported packet ({1}). Closing connection.", ClientId, packet); | |||||
_logger.LogWarning("Client '{0}': Received not supported packet ({1}). Closing connection.", ClientId, packet); | |||||
Stop(); | Stop(); | ||||
} | } | ||||
} | } | ||||
@@ -4,26 +4,28 @@ using System.Linq; | |||||
using System.Threading; | using System.Threading; | ||||
using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
using MQTTnet.Core.Adapter; | using MQTTnet.Core.Adapter; | ||||
using MQTTnet.Core.Diagnostics; | |||||
using MQTTnet.Core.Exceptions; | using MQTTnet.Core.Exceptions; | ||||
using MQTTnet.Core.Internal; | using MQTTnet.Core.Internal; | ||||
using MQTTnet.Core.Packets; | using MQTTnet.Core.Packets; | ||||
using MQTTnet.Core.Protocol; | using MQTTnet.Core.Protocol; | ||||
using MQTTnet.Core.Serializer; | using MQTTnet.Core.Serializer; | ||||
using Microsoft.Extensions.Logging; | |||||
using Microsoft.Extensions.Options; | |||||
namespace MQTTnet.Core.Server | namespace MQTTnet.Core.Server | ||||
{ | { | ||||
public sealed class MqttClientSessionsManager | public sealed class MqttClientSessionsManager | ||||
{ | { | ||||
private readonly Dictionary<string, MqttClientSession> _clientSessions = new Dictionary<string, MqttClientSession>(); | private readonly Dictionary<string, MqttClientSession> _clientSessions = new Dictionary<string, MqttClientSession>(); | ||||
private readonly MqttServerOptions _options; | |||||
private readonly MqttNetTrace _trace; | |||||
private readonly ILogger<MqttClientSessionsManager> _logger; | |||||
private readonly IMqttClientSesssionFactory _mqttClientSesssionFactory; | |||||
public MqttClientSessionsManager(MqttServerOptions options, MqttNetTrace trace) | |||||
public MqttClientSessionsManager(IOptions<MqttServerOptions> options, ILogger<MqttClientSessionsManager> logger, MqttClientRetainedMessagesManager retainedMessagesManager, IMqttClientSesssionFactory mqttClientSesssionFactory) | |||||
{ | { | ||||
_trace = trace ?? throw new ArgumentNullException(nameof(trace)); | |||||
_options = options ?? throw new ArgumentNullException(nameof(options)); | |||||
RetainedMessagesManager = new MqttClientRetainedMessagesManager(options, trace); | |||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger)); | |||||
Options = options.Value ?? throw new ArgumentNullException(nameof(options)); | |||||
RetainedMessagesManager = retainedMessagesManager ?? throw new ArgumentNullException(nameof(options)); | |||||
_mqttClientSesssionFactory = mqttClientSesssionFactory ?? throw new ArgumentNullException(nameof(mqttClientSesssionFactory)); | |||||
} | } | ||||
public event EventHandler<MqttApplicationMessageReceivedEventArgs> ApplicationMessageReceived; | public event EventHandler<MqttApplicationMessageReceivedEventArgs> ApplicationMessageReceived; | ||||
@@ -31,13 +33,14 @@ namespace MQTTnet.Core.Server | |||||
public event EventHandler<MqttClientDisconnectedEventArgs> ClientDisconnected; | public event EventHandler<MqttClientDisconnectedEventArgs> ClientDisconnected; | ||||
public MqttClientRetainedMessagesManager RetainedMessagesManager { get; } | public MqttClientRetainedMessagesManager RetainedMessagesManager { get; } | ||||
public MqttServerOptions Options { get; } | |||||
public async Task RunClientSessionAsync(IMqttCommunicationAdapter clientAdapter) | public async Task RunClientSessionAsync(IMqttCommunicationAdapter clientAdapter) | ||||
{ | { | ||||
var clientId = string.Empty; | var clientId = string.Empty; | ||||
try | try | ||||
{ | { | ||||
if (!(await clientAdapter.ReceivePacketAsync(_options.DefaultCommunicationTimeout, CancellationToken.None).ConfigureAwait(false) is MqttConnectPacket connectPacket)) | |||||
if (!(await clientAdapter.ReceivePacketAsync(Options.DefaultCommunicationTimeout, CancellationToken.None).ConfigureAwait(false) is MqttConnectPacket connectPacket)) | |||||
{ | { | ||||
throw new MqttProtocolViolationException("The first packet from a client must be a 'CONNECT' packet [MQTT-3.1.0-1]."); | throw new MqttProtocolViolationException("The first packet from a client must be a 'CONNECT' packet [MQTT-3.1.0-1]."); | ||||
} | } | ||||
@@ -50,7 +53,7 @@ namespace MQTTnet.Core.Server | |||||
var connectReturnCode = ValidateConnection(connectPacket); | var connectReturnCode = ValidateConnection(connectPacket); | ||||
if (connectReturnCode != MqttConnectReturnCode.ConnectionAccepted) | if (connectReturnCode != MqttConnectReturnCode.ConnectionAccepted) | ||||
{ | { | ||||
await clientAdapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, CancellationToken.None, new MqttConnAckPacket | |||||
await clientAdapter.SendPacketsAsync(Options.DefaultCommunicationTimeout, CancellationToken.None, new MqttConnAckPacket | |||||
{ | { | ||||
ConnectReturnCode = connectReturnCode | ConnectReturnCode = connectReturnCode | ||||
}).ConfigureAwait(false); | }).ConfigureAwait(false); | ||||
@@ -60,7 +63,7 @@ namespace MQTTnet.Core.Server | |||||
var clientSession = GetOrCreateClientSession(connectPacket); | var clientSession = GetOrCreateClientSession(connectPacket); | ||||
await clientAdapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, CancellationToken.None, new MqttConnAckPacket | |||||
await clientAdapter.SendPacketsAsync(Options.DefaultCommunicationTimeout, CancellationToken.None, new MqttConnAckPacket | |||||
{ | { | ||||
ConnectReturnCode = connectReturnCode, | ConnectReturnCode = connectReturnCode, | ||||
IsSessionPresent = clientSession.IsExistingSession | IsSessionPresent = clientSession.IsExistingSession | ||||
@@ -72,17 +75,20 @@ namespace MQTTnet.Core.Server | |||||
ProtocolVersion = clientAdapter.PacketSerializer.ProtocolVersion | ProtocolVersion = clientAdapter.PacketSerializer.ProtocolVersion | ||||
})); | })); | ||||
await clientSession.Session.RunAsync(connectPacket.WillMessage, clientAdapter).ConfigureAwait(false); | |||||
using (_logger.BeginScope(clientId)) | |||||
{ | |||||
await clientSession.Session.RunAsync(connectPacket.WillMessage, clientAdapter).ConfigureAwait(false); | |||||
} | |||||
} | } | ||||
catch (Exception exception) | catch (Exception exception) | ||||
{ | { | ||||
_trace.Error(nameof(MqttServer), exception, exception.Message); | |||||
_logger.LogError(new EventId(), exception, exception.Message); | |||||
} | } | ||||
finally | finally | ||||
{ | { | ||||
try | try | ||||
{ | { | ||||
await clientAdapter.DisconnectAsync(_options.DefaultCommunicationTimeout).ConfigureAwait(false); | |||||
await clientAdapter.DisconnectAsync(Options.DefaultCommunicationTimeout).ConfigureAwait(false); | |||||
} | } | ||||
catch (Exception) | catch (Exception) | ||||
{ | { | ||||
@@ -126,7 +132,7 @@ namespace MQTTnet.Core.Server | |||||
} | } | ||||
catch (Exception exception) | catch (Exception exception) | ||||
{ | { | ||||
_trace.Error(nameof(MqttClientSessionsManager), exception, "Error while processing application message"); | |||||
_logger.LogError(new EventId(), exception, "Error while processing application message"); | |||||
} | } | ||||
lock (_clientSessions) | lock (_clientSessions) | ||||
@@ -140,9 +146,9 @@ namespace MQTTnet.Core.Server | |||||
private MqttConnectReturnCode ValidateConnection(MqttConnectPacket connectPacket) | private MqttConnectReturnCode ValidateConnection(MqttConnectPacket connectPacket) | ||||
{ | { | ||||
if (_options.ConnectionValidator != null) | |||||
if (Options.ConnectionValidator != null) | |||||
{ | { | ||||
return _options.ConnectionValidator(connectPacket); | |||||
return Options.ConnectionValidator(connectPacket); | |||||
} | } | ||||
return MqttConnectReturnCode.ConnectionAccepted; | return MqttConnectReturnCode.ConnectionAccepted; | ||||
@@ -160,11 +166,11 @@ namespace MQTTnet.Core.Server | |||||
_clientSessions.Remove(connectPacket.ClientId); | _clientSessions.Remove(connectPacket.ClientId); | ||||
clientSession.Dispose(); | clientSession.Dispose(); | ||||
clientSession = null; | clientSession = null; | ||||
_trace.Verbose(nameof(MqttClientSessionsManager), "Disposed existing session of client '{0}'.", connectPacket.ClientId); | |||||
_logger.LogTrace("Disposed existing session of client '{0}'.", connectPacket.ClientId); | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
_trace.Verbose(nameof(MqttClientSessionsManager), "Reusing existing session of client '{0}'.", connectPacket.ClientId); | |||||
_logger.LogTrace("Reusing existing session of client '{0}'.", connectPacket.ClientId); | |||||
} | } | ||||
} | } | ||||
@@ -173,10 +179,10 @@ namespace MQTTnet.Core.Server | |||||
{ | { | ||||
isExistingSession = false; | isExistingSession = false; | ||||
clientSession = new MqttClientSession(connectPacket.ClientId, _options, this, _trace); | |||||
clientSession = _mqttClientSesssionFactory.CreateClientSession(connectPacket.ClientId, this); | |||||
_clientSessions[connectPacket.ClientId] = clientSession; | _clientSessions[connectPacket.ClientId] = clientSession; | ||||
_trace.Verbose(nameof(MqttClientSessionsManager), "Created a new session for client '{0}'.", connectPacket.ClientId); | |||||
_logger.LogTrace("Created a new session for client '{0}'.", connectPacket.ClientId); | |||||
} | } | ||||
return new GetOrCreateClientSessionResult { IsExistingSession = isExistingSession, Session = clientSession }; | return new GetOrCreateClientSessionResult { IsExistingSession = isExistingSession, Session = clientSession }; | ||||
@@ -3,26 +3,33 @@ using System.Collections.Generic; | |||||
using System.Threading; | using System.Threading; | ||||
using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
using MQTTnet.Core.Adapter; | using MQTTnet.Core.Adapter; | ||||
using MQTTnet.Core.Diagnostics; | |||||
using Microsoft.Extensions.Logging; | |||||
using Microsoft.Extensions.Options; | |||||
using System.Linq; | |||||
namespace MQTTnet.Core.Server | namespace MQTTnet.Core.Server | ||||
{ | { | ||||
public sealed class MqttServer : IMqttServer | public sealed class MqttServer : IMqttServer | ||||
{ | { | ||||
private readonly MqttNetTrace _trace; | |||||
private readonly ILogger<MqttServer> _logger; | |||||
private readonly MqttClientSessionsManager _clientSessionsManager; | private readonly MqttClientSessionsManager _clientSessionsManager; | ||||
private readonly ICollection<IMqttServerAdapter> _adapters; | private readonly ICollection<IMqttServerAdapter> _adapters; | ||||
private readonly MqttServerOptions _options; | private readonly MqttServerOptions _options; | ||||
private CancellationTokenSource _cancellationTokenSource; | private CancellationTokenSource _cancellationTokenSource; | ||||
public MqttServer(MqttServerOptions options, ICollection<IMqttServerAdapter> adapters, MqttNetTrace trace) | |||||
public MqttServer(IOptions<MqttServerOptions> options, IEnumerable<IMqttServerAdapter> adapters, ILogger<MqttServer> logger, MqttClientSessionsManager clientSessionsManager) | |||||
{ | { | ||||
_trace = trace ?? throw new ArgumentNullException(nameof(trace)); | |||||
_options = options ?? throw new ArgumentNullException(nameof(options)); | |||||
_adapters = adapters ?? throw new ArgumentNullException(nameof(adapters)); | |||||
_options = options.Value ?? throw new ArgumentNullException(nameof(options)); | |||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger)); | |||||
_clientSessionsManager = clientSessionsManager ?? throw new ArgumentNullException(nameof(clientSessionsManager)); | |||||
if (adapters == null) | |||||
{ | |||||
throw new ArgumentNullException(nameof(adapters)); | |||||
} | |||||
_adapters = adapters.ToList(); | |||||
_clientSessionsManager = new MqttClientSessionsManager(options, trace); | |||||
_clientSessionsManager.ApplicationMessageReceived += (s, e) => ApplicationMessageReceived?.Invoke(s, e); | _clientSessionsManager.ApplicationMessageReceived += (s, e) => ApplicationMessageReceived?.Invoke(s, e); | ||||
_clientSessionsManager.ClientConnected += OnClientConnected; | _clientSessionsManager.ClientConnected += OnClientConnected; | ||||
_clientSessionsManager.ClientDisconnected += OnClientDisconnected; | _clientSessionsManager.ClientDisconnected += OnClientDisconnected; | ||||
@@ -59,7 +66,7 @@ namespace MQTTnet.Core.Server | |||||
await adapter.StartAsync(_options); | await adapter.StartAsync(_options); | ||||
} | } | ||||
_trace.Information(nameof(MqttServer), "Started."); | |||||
_logger.LogInformation("Started."); | |||||
} | } | ||||
public async Task StopAsync() | public async Task StopAsync() | ||||
@@ -76,7 +83,7 @@ namespace MQTTnet.Core.Server | |||||
_clientSessionsManager.Clear(); | _clientSessionsManager.Clear(); | ||||
_trace.Information(nameof(MqttServer), "Stopped."); | |||||
_logger.LogInformation("Stopped."); | |||||
} | } | ||||
private void OnClientAccepted(object sender, MqttServerAdapterClientAcceptedEventArgs eventArgs) | private void OnClientAccepted(object sender, MqttServerAdapterClientAcceptedEventArgs eventArgs) | ||||
@@ -86,13 +93,13 @@ namespace MQTTnet.Core.Server | |||||
private void OnClientConnected(object sender, MqttClientConnectedEventArgs eventArgs) | private void OnClientConnected(object sender, MqttClientConnectedEventArgs eventArgs) | ||||
{ | { | ||||
_trace.Information(nameof(MqttServer), "Client '{0}': Connected.", eventArgs.Client.ClientId); | |||||
_logger.LogInformation("Client '{0}': Connected.", eventArgs.Client.ClientId); | |||||
ClientConnected?.Invoke(this, eventArgs); | ClientConnected?.Invoke(this, eventArgs); | ||||
} | } | ||||
private void OnClientDisconnected(object sender, MqttClientDisconnectedEventArgs eventArgs) | private void OnClientDisconnected(object sender, MqttClientDisconnectedEventArgs eventArgs) | ||||
{ | { | ||||
_trace.Information(nameof(MqttServer), "Client '{0}': Disconnected.", eventArgs.Client.ClientId); | |||||
_logger.LogInformation("Client '{0}': Disconnected.", eventArgs.Client.ClientId); | |||||
ClientDisconnected?.Invoke(this, eventArgs); | ClientDisconnected?.Invoke(this, eventArgs); | ||||
} | } | ||||
} | } | ||||
@@ -7,6 +7,7 @@ | |||||
</PropertyGroup> | </PropertyGroup> | ||||
<ItemGroup> | <ItemGroup> | ||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="1.1.2" /> | |||||
<PackageReference Include="MSTest.TestAdapter" Version="1.1.18" /> | <PackageReference Include="MSTest.TestAdapter" Version="1.1.18" /> | ||||
<PackageReference Include="MSTest.TestFramework" Version="1.1.18" /> | <PackageReference Include="MSTest.TestFramework" Version="1.1.18" /> | ||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.3.0" /> | <PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.3.0" /> | ||||
@@ -1,4 +1,5 @@ | |||||
using MQTTnet.Core.Adapter; | using MQTTnet.Core.Adapter; | ||||
using MQTTnet.Core.Channel; | |||||
using MQTTnet.Core.Client; | using MQTTnet.Core.Client; | ||||
namespace MQTTnet.Core.Tests | namespace MQTTnet.Core.Tests | ||||
@@ -12,7 +13,12 @@ namespace MQTTnet.Core.Tests | |||||
_adapter = adapter; | _adapter = adapter; | ||||
} | } | ||||
public IMqttCommunicationAdapter CreateMqttCommunicationAdapter(IMqttClientOptions options) | |||||
public IMqttCommunicationAdapter CreateClientMqttCommunicationAdapter(IMqttClientOptions options) | |||||
{ | |||||
return _adapter; | |||||
} | |||||
public IMqttCommunicationAdapter CreateServerMqttCommunicationAdapter(IMqttCommunicationChannel channel) | |||||
{ | { | ||||
return _adapter; | return _adapter; | ||||
} | } | ||||
@@ -5,10 +5,10 @@ using System.Threading.Tasks; | |||||
using Microsoft.VisualStudio.TestTools.UnitTesting; | using Microsoft.VisualStudio.TestTools.UnitTesting; | ||||
using MQTTnet.Core.Adapter; | using MQTTnet.Core.Adapter; | ||||
using MQTTnet.Core.Client; | using MQTTnet.Core.Client; | ||||
using MQTTnet.Core.Diagnostics; | |||||
using MQTTnet.Core.Packets; | using MQTTnet.Core.Packets; | ||||
using MQTTnet.Core.Protocol; | using MQTTnet.Core.Protocol; | ||||
using MQTTnet.Core.Server; | using MQTTnet.Core.Server; | ||||
using Microsoft.Extensions.DependencyInjection; | |||||
namespace MQTTnet.Core.Tests | namespace MQTTnet.Core.Tests | ||||
{ | { | ||||
@@ -52,7 +52,12 @@ namespace MQTTnet.Core.Tests | |||||
public async Task MqttServer_WillMessage() | public async Task MqttServer_WillMessage() | ||||
{ | { | ||||
var serverAdapter = new TestMqttServerAdapter(); | var serverAdapter = new TestMqttServerAdapter(); | ||||
var s = new MqttServer(new MqttServerOptions(), new List<IMqttServerAdapter> { serverAdapter }, new MqttNetTrace()); | |||||
var services = new ServiceCollection() | |||||
.AddMqttServer() | |||||
.AddSingleton<IMqttServerAdapter>(serverAdapter) | |||||
.BuildServiceProvider(); | |||||
var s = services.GetRequiredService<IMqttServer>(); | |||||
await s.StartAsync(); | await s.StartAsync(); | ||||
var willMessage = new MqttApplicationMessageBuilder().WithTopic("My/last/will").WithAtMostOnceQoS().Build(); | var willMessage = new MqttApplicationMessageBuilder().WithTopic("My/last/will").WithAtMostOnceQoS().Build(); | ||||
@@ -76,7 +81,12 @@ namespace MQTTnet.Core.Tests | |||||
public async Task MqttServer_Unsubscribe() | public async Task MqttServer_Unsubscribe() | ||||
{ | { | ||||
var serverAdapter = new TestMqttServerAdapter(); | var serverAdapter = new TestMqttServerAdapter(); | ||||
var s = new MqttServer(new MqttServerOptions(), new List<IMqttServerAdapter> { serverAdapter }, new MqttNetTrace()); | |||||
var services = new ServiceCollection() | |||||
.AddMqttServer() | |||||
.AddSingleton<IMqttServerAdapter>(serverAdapter) | |||||
.BuildServiceProvider(); | |||||
var s = services.GetRequiredService<IMqttServer>(); | |||||
await s.StartAsync(); | await s.StartAsync(); | ||||
var c1 = await serverAdapter.ConnectTestClient(s, "c1"); | var c1 = await serverAdapter.ConnectTestClient(s, "c1"); | ||||
@@ -112,7 +122,12 @@ namespace MQTTnet.Core.Tests | |||||
public async Task MqttServer_Publish() | public async Task MqttServer_Publish() | ||||
{ | { | ||||
var serverAdapter = new TestMqttServerAdapter(); | var serverAdapter = new TestMqttServerAdapter(); | ||||
var s = new MqttServer(new MqttServerOptions(), new List<IMqttServerAdapter> { serverAdapter }, new MqttNetTrace()); | |||||
var services = new ServiceCollection() | |||||
.AddMqttServer() | |||||
.AddSingleton<IMqttServerAdapter>(serverAdapter) | |||||
.BuildServiceProvider(); | |||||
var s = services.GetRequiredService<IMqttServer>(); | |||||
await s.StartAsync(); | await s.StartAsync(); | ||||
var c1 = await serverAdapter.ConnectTestClient(s, "c1"); | var c1 = await serverAdapter.ConnectTestClient(s, "c1"); | ||||
@@ -135,7 +150,12 @@ namespace MQTTnet.Core.Tests | |||||
public async Task MqttServer_NoRetainedMessage() | public async Task MqttServer_NoRetainedMessage() | ||||
{ | { | ||||
var serverAdapter = new TestMqttServerAdapter(); | var serverAdapter = new TestMqttServerAdapter(); | ||||
var s = new MqttServer(new MqttServerOptions(), new List<IMqttServerAdapter> { serverAdapter }, new MqttNetTrace()); | |||||
var services = new ServiceCollection() | |||||
.AddMqttServer() | |||||
.AddSingleton<IMqttServerAdapter>(serverAdapter) | |||||
.BuildServiceProvider(); | |||||
var s = services.GetRequiredService<IMqttServer>(); | |||||
await s.StartAsync(); | await s.StartAsync(); | ||||
var c1 = await serverAdapter.ConnectTestClient(s, "c1"); | var c1 = await serverAdapter.ConnectTestClient(s, "c1"); | ||||
@@ -158,7 +178,12 @@ namespace MQTTnet.Core.Tests | |||||
public async Task MqttServer_RetainedMessage() | public async Task MqttServer_RetainedMessage() | ||||
{ | { | ||||
var serverAdapter = new TestMqttServerAdapter(); | var serverAdapter = new TestMqttServerAdapter(); | ||||
var s = new MqttServer(new MqttServerOptions(), new List<IMqttServerAdapter> { serverAdapter }, new MqttNetTrace()); | |||||
var services = new ServiceCollection() | |||||
.AddMqttServer() | |||||
.AddSingleton<IMqttServerAdapter>(serverAdapter) | |||||
.BuildServiceProvider(); | |||||
var s = services.GetRequiredService<IMqttServer>(); | |||||
await s.StartAsync(); | await s.StartAsync(); | ||||
var c1 = await serverAdapter.ConnectTestClient(s, "c1"); | var c1 = await serverAdapter.ConnectTestClient(s, "c1"); | ||||
@@ -181,7 +206,12 @@ namespace MQTTnet.Core.Tests | |||||
public async Task MqttServer_ClearRetainedMessage() | public async Task MqttServer_ClearRetainedMessage() | ||||
{ | { | ||||
var serverAdapter = new TestMqttServerAdapter(); | var serverAdapter = new TestMqttServerAdapter(); | ||||
var s = new MqttServer(new MqttServerOptions(), new List<IMqttServerAdapter> { serverAdapter }, new MqttNetTrace()); | |||||
var services = new ServiceCollection() | |||||
.AddMqttServer() | |||||
.AddSingleton<IMqttServerAdapter>(serverAdapter) | |||||
.BuildServiceProvider(); | |||||
var s = services.GetRequiredService<IMqttServer>(); | |||||
await s.StartAsync(); | await s.StartAsync(); | ||||
var c1 = await serverAdapter.ConnectTestClient(s, "c1"); | var c1 = await serverAdapter.ConnectTestClient(s, "c1"); | ||||
@@ -207,7 +237,12 @@ namespace MQTTnet.Core.Tests | |||||
var storage = new TestStorage(); | var storage = new TestStorage(); | ||||
var serverAdapter = new TestMqttServerAdapter(); | var serverAdapter = new TestMqttServerAdapter(); | ||||
var s = new MqttServer(new MqttServerOptions { Storage = storage }, new List<IMqttServerAdapter> { serverAdapter }, new MqttNetTrace()); | |||||
var services = new ServiceCollection() | |||||
.AddMqttServer() | |||||
.AddSingleton<IMqttServerAdapter>(serverAdapter) | |||||
.BuildServiceProvider(); | |||||
var s = services.GetRequiredService<IMqttServer>(); | |||||
await s.StartAsync(); | await s.StartAsync(); | ||||
var c1 = await serverAdapter.ConnectTestClient(s, "c1"); | var c1 = await serverAdapter.ConnectTestClient(s, "c1"); | ||||
@@ -216,7 +251,7 @@ namespace MQTTnet.Core.Tests | |||||
await s.StopAsync(); | await s.StopAsync(); | ||||
s = new MqttServer(new MqttServerOptions { Storage = storage }, new List<IMqttServerAdapter> { serverAdapter }, new MqttNetTrace()); | |||||
s = services.GetRequiredService<IMqttServer>(); | |||||
await s.StartAsync(); | await s.StartAsync(); | ||||
var c2 = await serverAdapter.ConnectTestClient(s, "c2"); | var c2 = await serverAdapter.ConnectTestClient(s, "c2"); | ||||
@@ -244,7 +279,12 @@ namespace MQTTnet.Core.Tests | |||||
}; | }; | ||||
var serverAdapter = new TestMqttServerAdapter(); | var serverAdapter = new TestMqttServerAdapter(); | ||||
var s = new MqttServer(options, new List<IMqttServerAdapter> { serverAdapter }, new MqttNetTrace()); | |||||
var services = new ServiceCollection() | |||||
.AddMqttServer() | |||||
.AddSingleton<IMqttServerAdapter>(serverAdapter) | |||||
.BuildServiceProvider(); | |||||
var s = services.GetRequiredService<IMqttServer>(); | |||||
await s.StartAsync(); | await s.StartAsync(); | ||||
var c1 = await serverAdapter.ConnectTestClient(s, "c1"); | var c1 = await serverAdapter.ConnectTestClient(s, "c1"); | ||||
@@ -290,7 +330,12 @@ namespace MQTTnet.Core.Tests | |||||
int expectedReceivedMessagesCount) | int expectedReceivedMessagesCount) | ||||
{ | { | ||||
var serverAdapter = new TestMqttServerAdapter(); | var serverAdapter = new TestMqttServerAdapter(); | ||||
var s = new MqttServer(new MqttServerOptions(), new List<IMqttServerAdapter> { serverAdapter }, new MqttNetTrace()); | |||||
var services = new ServiceCollection() | |||||
.AddMqttServer() | |||||
.AddSingleton<IMqttServerAdapter>(serverAdapter) | |||||
.BuildServiceProvider(); | |||||
var s = services.GetRequiredService<IMqttServer>(); | |||||
await s.StartAsync(); | await s.StartAsync(); | ||||
var c1 = await serverAdapter.ConnectTestClient(s, "c1"); | var c1 = await serverAdapter.ConnectTestClient(s, "c1"); | ||||
@@ -0,0 +1,30 @@ | |||||
using Microsoft.Extensions.DependencyInjection; | |||||
using Microsoft.VisualStudio.TestTools.UnitTesting; | |||||
namespace MQTTnet.Core.Tests | |||||
{ | |||||
[TestClass] | |||||
public class ServiceCollectionTest | |||||
{ | |||||
[TestMethod] | |||||
public void TestCanConstructAllServices() | |||||
{ | |||||
var services = new ServiceCollection() | |||||
.AddLogging() | |||||
.AddMqttServer() | |||||
.AddMqttClient(); | |||||
var serviceProvider = services | |||||
.BuildServiceProvider(); | |||||
foreach (var service in services) | |||||
{ | |||||
if (service.ServiceType.IsGenericType) | |||||
{ | |||||
continue; | |||||
} | |||||
serviceProvider.GetRequiredService(service.ServiceType); | |||||
} | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,12 @@ | |||||
using MQTTnet.Core.Server; | |||||
namespace MQTTnet.Core.Tests | |||||
{ | |||||
public class TestClientSessionFactory : IMqttClientSesssionFactory | |||||
{ | |||||
public MqttClientSession CreateClientSession(string sessionId, MqttClientSessionsManager mqttClientSessionsManager) | |||||
{ | |||||
return new MqttClientSession(sessionId, mqttClientSessionsManager, new TestLogger<MqttClientSession>(), new TestLogger<MqttClientPendingMessagesQueue>()); | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,22 @@ | |||||
using Microsoft.Extensions.Logging; | |||||
using System; | |||||
namespace MQTTnet.Core.Tests | |||||
{ | |||||
public class TestLogger<T> : ILogger<T> | |||||
{ | |||||
public IDisposable BeginScope<TState>(TState state) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public bool IsEnabled(LogLevel logLevel) | |||||
{ | |||||
return true; | |||||
} | |||||
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter) | |||||
{ | |||||
} | |||||
} | |||||
} |
@@ -3,7 +3,6 @@ using System.Threading.Tasks; | |||||
using MQTTnet.Core.Adapter; | using MQTTnet.Core.Adapter; | ||||
using MQTTnet.Core.Server; | using MQTTnet.Core.Server; | ||||
using MQTTnet.Core.Client; | using MQTTnet.Core.Client; | ||||
using MQTTnet.Core.Diagnostics; | |||||
namespace MQTTnet.Core.Tests | namespace MQTTnet.Core.Tests | ||||
{ | { | ||||
@@ -18,7 +17,7 @@ namespace MQTTnet.Core.Tests | |||||
adapterA.Partner = adapterB; | adapterA.Partner = adapterB; | ||||
adapterB.Partner = adapterA; | adapterB.Partner = adapterA; | ||||
var client = new MqttClient(new MqttCommunicationAdapterFactory(adapterA), new MqttNetTrace()); | |||||
var client = new MqttClient(new MqttCommunicationAdapterFactory(adapterA), new TestLogger<MqttClient>(), new MqttPacketDispatcher(new TestLogger<MqttPacketDispatcher>())); | |||||
var connected = WaitForClientToConnect(server, clientId); | var connected = WaitForClientToConnect(server, clientId); | ||||
FireClientAcceptedEvent(adapterB); | FireClientAcceptedEvent(adapterB); | ||||
@@ -5,20 +5,22 @@ using System.Threading; | |||||
using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
using MQTTnet.Core.Adapter; | using MQTTnet.Core.Adapter; | ||||
using MQTTnet.Core.Channel; | using MQTTnet.Core.Channel; | ||||
using MQTTnet.Core.Diagnostics; | |||||
using MQTTnet.Core.Serializer; | using MQTTnet.Core.Serializer; | ||||
using MQTTnet.Core.Server; | using MQTTnet.Core.Server; | ||||
using MQTTnet.Implementations; | using MQTTnet.Implementations; | ||||
using Microsoft.Extensions.Logging; | |||||
namespace MQTTnet.TestApp.AspNetCore2 | namespace MQTTnet.TestApp.AspNetCore2 | ||||
{ | { | ||||
public class MqttWebSocketServerAdapter : IMqttServerAdapter, IDisposable | public class MqttWebSocketServerAdapter : IMqttServerAdapter, IDisposable | ||||
{ | { | ||||
private readonly MqttNetTrace _trace; | |||||
private readonly ILogger<MqttWebSocketServerAdapter> _logger; | |||||
private readonly IMqttCommunicationAdapterFactory _mqttCommunicationAdapterFactory; | |||||
public MqttWebSocketServerAdapter(MqttNetTrace trace) | |||||
public MqttWebSocketServerAdapter(ILogger<MqttWebSocketServerAdapter> logger, IMqttCommunicationAdapterFactory mqttCommunicationAdapterFactory) | |||||
{ | { | ||||
_trace = trace ?? throw new ArgumentNullException(nameof(trace)); | |||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger)); | |||||
_mqttCommunicationAdapterFactory = mqttCommunicationAdapterFactory ?? throw new ArgumentNullException(nameof(mqttCommunicationAdapterFactory)); | |||||
} | } | ||||
public event EventHandler<MqttServerAdapterClientAcceptedEventArgs> ClientAccepted; | public event EventHandler<MqttServerAdapterClientAcceptedEventArgs> ClientAccepted; | ||||
@@ -38,7 +40,7 @@ namespace MQTTnet.TestApp.AspNetCore2 | |||||
if (webSocket == null) throw new ArgumentNullException(nameof(webSocket)); | if (webSocket == null) throw new ArgumentNullException(nameof(webSocket)); | ||||
var channel = new MqttWebSocketServerChannel(webSocket); | var channel = new MqttWebSocketServerChannel(webSocket); | ||||
var clientAdapter = new MqttChannelCommunicationAdapter(channel, new MqttPacketSerializer(), _trace); | |||||
var clientAdapter = _mqttCommunicationAdapterFactory.CreateServerMqttCommunicationAdapter(channel); | |||||
var eventArgs = new MqttServerAdapterClientAcceptedEventArgs(clientAdapter); | var eventArgs = new MqttServerAdapterClientAcceptedEventArgs(clientAdapter); | ||||
ClientAccepted?.Invoke(this, eventArgs); | ClientAccepted?.Invoke(this, eventArgs); | ||||
@@ -5,7 +5,6 @@ using Microsoft.AspNetCore.Hosting; | |||||
using Microsoft.Extensions.DependencyInjection; | using Microsoft.Extensions.DependencyInjection; | ||||
using Microsoft.Extensions.Logging; | using Microsoft.Extensions.Logging; | ||||
using MQTTnet.Core.Adapter; | using MQTTnet.Core.Adapter; | ||||
using MQTTnet.Core.Diagnostics; | |||||
using MQTTnet.Core.Server; | using MQTTnet.Core.Server; | ||||
namespace MQTTnet.TestApp.AspNetCore2 | namespace MQTTnet.TestApp.AspNetCore2 | ||||
@@ -14,25 +13,18 @@ namespace MQTTnet.TestApp.AspNetCore2 | |||||
{ | { | ||||
public void ConfigureServices(IServiceCollection services) | public void ConfigureServices(IServiceCollection services) | ||||
{ | { | ||||
services.AddMqttServer(); | |||||
services.AddSingleton<MqttWebSocketServerAdapter>(); | |||||
services.AddSingleton<IMqttServerAdapter, MqttWebSocketServerAdapter>(); | |||||
} | } | ||||
public async void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) | public async void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) | ||||
{ | { | ||||
loggerFactory.AddConsole(LogLevel.Debug); | loggerFactory.AddConsole(LogLevel.Debug); | ||||
loggerFactory.AddDebug(); | |||||
MqttNetTrace.TraceMessagePublished += (s, e) => | |||||
{ | |||||
Debug.WriteLine($">> [{e.TraceMessage.Timestamp}] [{e.TraceMessage.ThreadId}] [{e.TraceMessage.Source}] [{e.TraceMessage.Level}]: {e.TraceMessage.Message}"); | |||||
if (e.TraceMessage.Exception != null) | |||||
{ | |||||
Debug.WriteLine(e.TraceMessage.Exception.Message); | |||||
} | |||||
}; | |||||
var trace = new MqttNetTrace(); | |||||
var adapter = new MqttWebSocketServerAdapter(trace); | |||||
var options = new MqttServerOptions(); | |||||
var mqttServer = new MqttServer(options, new List<IMqttServerAdapter> { adapter }, new MqttNetTrace()); | |||||
var adapter = app.ApplicationServices.GetService<MqttWebSocketServerAdapter>(); | |||||
var mqttServer = app.ApplicationServices.GetService<IMqttServer>(); | |||||
await mqttServer.StartAsync(); | await mqttServer.StartAsync(); | ||||
app.UseWebSockets(); | app.UseWebSockets(); | ||||
@@ -3,10 +3,11 @@ | |||||
<PropertyGroup> | <PropertyGroup> | ||||
<OutputType>Exe</OutputType> | <OutputType>Exe</OutputType> | ||||
<DebugType>Full</DebugType> | <DebugType>Full</DebugType> | ||||
<TargetFrameworks>netcoreapp2.0;net45</TargetFrameworks> | |||||
<TargetFrameworks>netcoreapp2.0;net451</TargetFrameworks> | |||||
</PropertyGroup> | </PropertyGroup> | ||||
<ItemGroup> | <ItemGroup> | ||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="1.1.2" /> | |||||
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" /> | <PackageReference Include="Newtonsoft.Json" Version="10.0.3" /> | ||||
</ItemGroup> | </ItemGroup> | ||||
@@ -15,4 +16,10 @@ | |||||
<ProjectReference Include="..\..\MQTTnet.Core\MQTTnet.Core.csproj" /> | <ProjectReference Include="..\..\MQTTnet.Core\MQTTnet.Core.csproj" /> | ||||
</ItemGroup> | </ItemGroup> | ||||
<ItemGroup> | |||||
<PackageReference Include="Microsoft.Extensions.Logging.Console"> | |||||
<Version>1.1.2</Version> | |||||
</PackageReference> | |||||
</ItemGroup> | |||||
</Project> | </Project> |
@@ -2,10 +2,11 @@ | |||||
using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
using MQTTnet.Core; | using MQTTnet.Core; | ||||
using MQTTnet.Core.Client; | using MQTTnet.Core.Client; | ||||
using MQTTnet.Core.Diagnostics; | |||||
using MQTTnet.Core.ManagedClient; | using MQTTnet.Core.ManagedClient; | ||||
using MQTTnet.Core.Packets; | using MQTTnet.Core.Packets; | ||||
using MQTTnet.Core.Protocol; | using MQTTnet.Core.Protocol; | ||||
using Microsoft.Extensions.DependencyInjection; | |||||
using Microsoft.Extensions.Logging; | |||||
namespace MQTTnet.TestApp.NetCore | namespace MQTTnet.TestApp.NetCore | ||||
{ | { | ||||
@@ -13,14 +14,14 @@ namespace MQTTnet.TestApp.NetCore | |||||
{ | { | ||||
public static async Task RunAsync() | public static async Task RunAsync() | ||||
{ | { | ||||
MqttNetTrace.TraceMessagePublished += (s, e) => | |||||
{ | |||||
Console.WriteLine($">> [{e.TraceMessage.Timestamp:O}] [{e.TraceMessage.ThreadId}] [{e.TraceMessage.Source}] [{e.TraceMessage.Level}]: {e.TraceMessage.Message}"); | |||||
if (e.TraceMessage.Exception != null) | |||||
{ | |||||
Console.WriteLine(e.TraceMessage.Exception); | |||||
} | |||||
}; | |||||
var services = new ServiceCollection() | |||||
.AddMqttClient() | |||||
.AddLogging() | |||||
.BuildServiceProvider(); | |||||
services.GetService<ILoggerFactory>() | |||||
.AddConsole(); | |||||
var options = new ManagedMqttClientOptions | var options = new ManagedMqttClientOptions | ||||
{ | { | ||||
@@ -35,7 +36,7 @@ namespace MQTTnet.TestApp.NetCore | |||||
try | try | ||||
{ | { | ||||
var managedClient = new MqttClientFactory().CreateManagedMqttClient(); | |||||
var managedClient = services.GetRequiredService<ManagedMqttClient>(); | |||||
managedClient.ApplicationMessageReceived += (s, e) => | managedClient.ApplicationMessageReceived += (s, e) => | ||||
{ | { | ||||
Console.WriteLine(">> RECEIVED: " + e.ApplicationMessage.Topic); | Console.WriteLine(">> RECEIVED: " + e.ApplicationMessage.Topic); | ||||
@@ -1,4 +1,6 @@ | |||||
using MQTTnet.Core; | |||||
using Microsoft.Extensions.DependencyInjection; | |||||
using Microsoft.Extensions.Logging; | |||||
using MQTTnet.Core; | |||||
using MQTTnet.Core.Client; | using MQTTnet.Core.Client; | ||||
using MQTTnet.Core.Packets; | using MQTTnet.Core.Packets; | ||||
using MQTTnet.Core.Protocol; | using MQTTnet.Core.Protocol; | ||||
@@ -17,33 +19,58 @@ namespace MQTTnet.TestApp.NetCore | |||||
{ | { | ||||
public static async Task RunAsync() | public static async Task RunAsync() | ||||
{ | { | ||||
var server = Task.Factory.StartNew(RunServerAsync, TaskCreationOptions.LongRunning); | |||||
var client = Task.Factory.StartNew(() => RunClientAsync(2000, TimeSpan.FromMilliseconds(10)), TaskCreationOptions.LongRunning); | |||||
var services = new ServiceCollection() | |||||
.AddMqttServer(options => { | |||||
options.ConnectionValidator = p => | |||||
{ | |||||
if (p.ClientId == "SpecialClient") | |||||
{ | |||||
if (p.Username != "USER" || p.Password != "PASS") | |||||
{ | |||||
return MqttConnectReturnCode.ConnectionRefusedBadUsernameOrPassword; | |||||
} | |||||
} | |||||
return MqttConnectReturnCode.ConnectionAccepted; | |||||
}; | |||||
options.DefaultCommunicationTimeout = TimeSpan.FromMinutes(10); | |||||
}) | |||||
.AddMqttClient() | |||||
.AddLogging() | |||||
.BuildServiceProvider(); | |||||
services.GetService<ILoggerFactory>() | |||||
.AddConsole(minLevel: LogLevel.Warning, includeScopes: true); | |||||
Console.WriteLine("Press 'c' for concurrent sends. Otherwise in one batch."); | |||||
var concurrent = Console.ReadKey(intercept: true).KeyChar == 'c'; | |||||
var server = Task.Factory.StartNew(() => RunServerAsync(services), TaskCreationOptions.LongRunning); | |||||
var client = Task.Factory.StartNew(() => RunClientAsync(2000, TimeSpan.FromMilliseconds(10), services, concurrent), TaskCreationOptions.LongRunning); | |||||
await Task.WhenAll(server, client).ConfigureAwait(false); | await Task.WhenAll(server, client).ConfigureAwait(false); | ||||
} | } | ||||
private static Task RunClientsAsync(int msgChunkSize, TimeSpan interval) | |||||
private static Task RunClientsAsync(int msgChunkSize, TimeSpan interval, IServiceProvider serviceProvider, bool concurrent) | |||||
{ | { | ||||
return Task.WhenAll(Enumerable.Range(0, 3).Select(i => Task.Run(() => RunClientAsync(msgChunkSize, interval)))); | |||||
return Task.WhenAll(Enumerable.Range(0, 3).Select(i => Task.Run(() => RunClientAsync(msgChunkSize, interval, serviceProvider, concurrent)))); | |||||
} | } | ||||
private static async Task RunClientAsync(int msgChunkSize, TimeSpan interval) | |||||
private static async Task RunClientAsync(int msgChunkSize, TimeSpan interval, IServiceProvider serviceProvider, bool concurrent) | |||||
{ | { | ||||
try | try | ||||
{ | { | ||||
var options = new MqttClientTcpOptions | var options = new MqttClientTcpOptions | ||||
{ | { | ||||
Server = "localhost", | Server = "localhost", | ||||
ClientId = "XYZ", | |||||
ClientId = "Client1", | |||||
CleanSession = true, | CleanSession = true, | ||||
DefaultCommunicationTimeout = TimeSpan.FromMinutes(10) | DefaultCommunicationTimeout = TimeSpan.FromMinutes(10) | ||||
}; | }; | ||||
var client = new MqttClientFactory().CreateMqttClient(); | |||||
client.ApplicationMessageReceived += (s, e) => | |||||
{ | |||||
}; | |||||
var client = serviceProvider.GetRequiredService<IMqttClient>(); | |||||
client.Connected += async (s, e) => | client.Connected += async (s, e) => | ||||
{ | { | ||||
@@ -113,8 +140,7 @@ namespace MQTTnet.TestApp.NetCore | |||||
.Select(i => CreateMessage()) | .Select(i => CreateMessage()) | ||||
.ToList(); | .ToList(); | ||||
Console.WriteLine("Press 'c' for concurrent sends. Otherwise in one batch."); | |||||
if (Console.ReadKey().KeyChar == 'c') | |||||
if (concurrent) | |||||
{ | { | ||||
//send concurrent (test for raceconditions) | //send concurrent (test for raceconditions) | ||||
var sendTasks = msgs | var sendTasks = msgs | ||||
@@ -165,28 +191,11 @@ namespace MQTTnet.TestApp.NetCore | |||||
return Task.Run(() => client.PublishAsync(applicationMessage)); | return Task.Run(() => client.PublishAsync(applicationMessage)); | ||||
} | } | ||||
private static async Task RunServerAsync() | |||||
private static async Task RunServerAsync(IServiceProvider serviceProvider) | |||||
{ | { | ||||
try | try | ||||
{ | { | ||||
var options = new MqttServerOptions | |||||
{ | |||||
ConnectionValidator = p => | |||||
{ | |||||
if (p.ClientId == "SpecialClient") | |||||
{ | |||||
if (p.Username != "USER" || p.Password != "PASS") | |||||
{ | |||||
return MqttConnectReturnCode.ConnectionRefusedBadUsernameOrPassword; | |||||
} | |||||
} | |||||
return MqttConnectReturnCode.ConnectionAccepted; | |||||
}, | |||||
DefaultCommunicationTimeout = TimeSpan.FromMinutes(10) | |||||
}; | |||||
var mqttServer = new MqttServerFactory().CreateMqttServer(options); | |||||
var mqttServer = serviceProvider.GetRequiredService<IMqttServer>(); | |||||
var msgs = 0; | var msgs = 0; | ||||
var stopwatch = Stopwatch.StartNew(); | var stopwatch = Stopwatch.StartNew(); | ||||
mqttServer.ApplicationMessageReceived += (sender, args) => | mqttServer.ApplicationMessageReceived += (sender, args) => | ||||
@@ -1,6 +1,5 @@ | |||||
using MQTTnet.Core; | using MQTTnet.Core; | ||||
using MQTTnet.Core.Client; | using MQTTnet.Core.Client; | ||||
using MQTTnet.Core.Diagnostics; | |||||
using MQTTnet.Core.Packets; | using MQTTnet.Core.Packets; | ||||
using MQTTnet.Core.Protocol; | using MQTTnet.Core.Protocol; | ||||
using MQTTnet.Core.Server; | using MQTTnet.Core.Server; | ||||
@@ -12,6 +11,8 @@ using System.Text; | |||||
using System.Threading; | using System.Threading; | ||||
using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
using Newtonsoft.Json; | using Newtonsoft.Json; | ||||
using Microsoft.Extensions.DependencyInjection; | |||||
using Microsoft.Extensions.Logging; | |||||
namespace MQTTnet.TestApp.NetCore | namespace MQTTnet.TestApp.NetCore | ||||
{ | { | ||||
@@ -24,7 +25,7 @@ namespace MQTTnet.TestApp.NetCore | |||||
Console.WriteLine("2 = Start server"); | Console.WriteLine("2 = Start server"); | ||||
Console.WriteLine("3 = Start performance test"); | Console.WriteLine("3 = Start performance test"); | ||||
Console.WriteLine("4 = Start managed client"); | Console.WriteLine("4 = Start managed client"); | ||||
var pressedKey = Console.ReadKey(true); | var pressedKey = Console.ReadKey(true); | ||||
if (pressedKey.KeyChar == '1') | if (pressedKey.KeyChar == '1') | ||||
{ | { | ||||
@@ -48,17 +49,16 @@ namespace MQTTnet.TestApp.NetCore | |||||
private static async Task RunClientAsync() | private static async Task RunClientAsync() | ||||
{ | { | ||||
MqttNetTrace.TraceMessagePublished += (s, e) => | |||||
{ | |||||
Console.WriteLine($">> [{e.TraceMessage.Timestamp:O}] [{e.TraceMessage.ThreadId}] [{e.TraceMessage.Source}] [{e.TraceMessage.Level}]: {e.TraceMessage.Message}"); | |||||
if (e.TraceMessage.Exception != null) | |||||
{ | |||||
Console.WriteLine(e.TraceMessage.Exception); | |||||
} | |||||
}; | |||||
try | try | ||||
{ | { | ||||
var services = new ServiceCollection() | |||||
.AddMqttServer() | |||||
.AddLogging() | |||||
.BuildServiceProvider(); | |||||
services.GetService<ILoggerFactory>() | |||||
.AddConsole(); | |||||
var options = new MqttClientWebSocketOptions | var options = new MqttClientWebSocketOptions | ||||
{ | { | ||||
Uri = "localhost", | Uri = "localhost", | ||||
@@ -66,7 +66,7 @@ namespace MQTTnet.TestApp.NetCore | |||||
CleanSession = true | CleanSession = true | ||||
}; | }; | ||||
var client = new MqttClientFactory().CreateMqttClient(); | |||||
var client = services.GetRequiredService<IMqttClient>(); | |||||
client.ApplicationMessageReceived += (s, e) => | client.ApplicationMessageReceived += (s, e) => | ||||
{ | { | ||||
Console.WriteLine("### RECEIVED APPLICATION MESSAGE ###"); | Console.WriteLine("### RECEIVED APPLICATION MESSAGE ###"); | ||||
@@ -139,7 +139,12 @@ namespace MQTTnet.TestApp.NetCore | |||||
private static async void WikiCode() | private static async void WikiCode() | ||||
{ | { | ||||
{ | { | ||||
var client = new MqttClientFactory().CreateMqttClient(new CustomTraceHandler("Client 1")); | |||||
var serviceProvider = new ServiceCollection() | |||||
.AddMqttServer() | |||||
.AddLogging() | |||||
.BuildServiceProvider(); | |||||
var client = serviceProvider.GetRequiredService<IMqttClient>(); | |||||
var message = new MqttApplicationMessageBuilder() | var message = new MqttApplicationMessageBuilder() | ||||
.WithTopic("MyTopic") | .WithTopic("MyTopic") | ||||
@@ -159,28 +164,6 @@ namespace MQTTnet.TestApp.NetCore | |||||
} | } | ||||
} | } | ||||
public class CustomTraceHandler : IMqttNetTraceHandler | |||||
{ | |||||
private readonly string _clientId; | |||||
public CustomTraceHandler(string clientId) | |||||
{ | |||||
_clientId = clientId; | |||||
} | |||||
public bool IsEnabled { get; } = true; | |||||
public void HandleTraceMessage(MqttNetTraceMessage traceMessage) | |||||
{ | |||||
// Client ID is added to the trace message. | |||||
Console.WriteLine($">> [{_clientId}] [{traceMessage.Timestamp:O}] [{traceMessage.ThreadId}] [{traceMessage.Source}] [{traceMessage.Level}]: {traceMessage.Message}"); | |||||
if (traceMessage.Exception != null) | |||||
{ | |||||
Console.WriteLine(traceMessage.Exception); | |||||
} | |||||
} | |||||
} | |||||
public class RetainedMessageHandler : IMqttServerStorage | public class RetainedMessageHandler : IMqttServerStorage | ||||
{ | { | ||||
private const string Filename = "C:\\MQTT\\RetainedMessages.json"; | private const string Filename = "C:\\MQTT\\RetainedMessages.json"; | ||||
@@ -1,9 +1,10 @@ | |||||
using System; | using System; | ||||
using System.Text; | using System.Text; | ||||
using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
using MQTTnet.Core.Diagnostics; | |||||
using MQTTnet.Core.Protocol; | using MQTTnet.Core.Protocol; | ||||
using MQTTnet.Core.Server; | using MQTTnet.Core.Server; | ||||
using Microsoft.Extensions.DependencyInjection; | |||||
using Microsoft.Extensions.Logging; | |||||
namespace MQTTnet.TestApp.NetCore | namespace MQTTnet.TestApp.NetCore | ||||
{ | { | ||||
@@ -11,20 +12,15 @@ namespace MQTTnet.TestApp.NetCore | |||||
{ | { | ||||
public static Task RunAsync() | public static Task RunAsync() | ||||
{ | { | ||||
MqttNetTrace.TraceMessagePublished += (s, e) => | |||||
{ | |||||
Console.WriteLine($">> [{e.TraceMessage.Timestamp:O}] [{e.TraceMessage.ThreadId}] [{e.TraceMessage.Source}] [{e.TraceMessage.Level}]: {e.TraceMessage.Message}"); | |||||
if (e.TraceMessage.Exception != null) | |||||
{ | |||||
Console.WriteLine(e.TraceMessage.Exception); | |||||
} | |||||
}; | |||||
try | try | ||||
{ | { | ||||
var options = new MqttServerOptions | |||||
var services = new ServiceCollection() | |||||
.AddMqttServer() | |||||
.AddLogging(); | |||||
services.Configure<MqttServerOptions>(options => | |||||
{ | { | ||||
ConnectionValidator = p => | |||||
options.ConnectionValidator = p => | |||||
{ | { | ||||
if (p.ClientId == "SpecialClient") | if (p.ClientId == "SpecialClient") | ||||
{ | { | ||||
@@ -35,22 +31,24 @@ namespace MQTTnet.TestApp.NetCore | |||||
} | } | ||||
return MqttConnectReturnCode.ConnectionAccepted; | return MqttConnectReturnCode.ConnectionAccepted; | ||||
} | |||||
}; | |||||
}; | |||||
options.Storage = new RetainedMessageHandler(); | |||||
options.Storage = new RetainedMessageHandler(); | |||||
options.ApplicationMessageInterceptor = message => | |||||
{ | |||||
if (MqttTopicFilterComparer.IsMatch(message.Topic, "/myTopic/WithTimestamp/#")) | |||||
options.ApplicationMessageInterceptor = message => | |||||
{ | { | ||||
// Replace the payload with the timestamp. But also extending a JSON | |||||
// based payload with the timestamp is a suitable use case. | |||||
message.Payload = Encoding.UTF8.GetBytes(DateTime.Now.ToString("O")); | |||||
} | |||||
if (MqttTopicFilterComparer.IsMatch(message.Topic, "/myTopic/WithTimestamp/#")) | |||||
{ | |||||
// Replace the payload with the timestamp. But also extending a JSON | |||||
// based payload with the timestamp is a suitable use case. | |||||
message.Payload = Encoding.UTF8.GetBytes(DateTime.Now.ToString("O")); | |||||
} | |||||
return message; | |||||
}; | |||||
return message; | |||||
}; | |||||
}); | |||||
var serviceProvider = services.BuildServiceProvider(); | |||||
//var certificate = new X509Certificate(@"C:\certs\test\test.cer", ""); | //var certificate = new X509Certificate(@"C:\certs\test\test.cer", ""); | ||||
//options.TlsEndpointOptions.Certificate = certificate.Export(X509ContentType.Cert); | //options.TlsEndpointOptions.Certificate = certificate.Export(X509ContentType.Cert); | ||||
@@ -58,7 +56,7 @@ namespace MQTTnet.TestApp.NetCore | |||||
//options.DefaultEndpointOptions.IsEnabled = true; | //options.DefaultEndpointOptions.IsEnabled = true; | ||||
//options.TlsEndpointOptions.IsEnabled = false; | //options.TlsEndpointOptions.IsEnabled = false; | ||||
var mqttServer = new MqttServerFactory().CreateMqttServer(options); | |||||
var mqttServer = serviceProvider.GetRequiredService<IMqttServer>(); | |||||
mqttServer.ClientDisconnected += (s, e) => | mqttServer.ClientDisconnected += (s, e) => | ||||
{ | { | ||||
Console.Write("Client disconnected event fired."); | Console.Write("Client disconnected event fired."); | ||||