@@ -28,7 +28,7 @@ namespace MQTTnet.AspNetCore | |||
} | |||
var adapter = app.ApplicationServices.GetRequiredService<MqttWebSocketServerAdapter>(); | |||
using (var webSocket = await context.WebSockets.AcceptWebSocketAsync(subProtocol)) | |||
using (var webSocket = await context.WebSockets.AcceptWebSocketAsync(subProtocol).ConfigureAwait(false)) | |||
{ | |||
await adapter.RunWebSocketConnectionAsync(webSocket, context); | |||
} | |||
@@ -24,8 +24,7 @@ namespace MQTTnet.AspNetCore | |||
_input = Connection.Transport.Input; | |||
_output = Connection.Transport.Output; | |||
} | |||
_reader = new SpanBasedMqttPacketBodyReader(); | |||
} | |||
@@ -33,9 +32,10 @@ namespace MQTTnet.AspNetCore | |||
private PipeWriter _output; | |||
private readonly SpanBasedMqttPacketBodyReader _reader; | |||
public string Endpoint | |||
public string Endpoint | |||
{ | |||
get { | |||
get | |||
{ | |||
var connection = Http?.HttpContext?.Connection; | |||
if (connection == null) | |||
{ | |||
@@ -53,12 +53,12 @@ namespace MQTTnet.AspNetCore | |||
public ConnectionContext Connection { get; } | |||
public MqttPacketFormatterAdapter PacketFormatterAdapter { get; } | |||
public long BytesSent { get; set; } | |||
public long BytesSent { get; set; } | |||
public long BytesReceived { get; set; } | |||
public Action ReadingPacketStartedCallback { get; set; } | |||
public Action ReadingPacketCompletedCallback { get; set; } | |||
private readonly SemaphoreSlim _writerSemaphore = new SemaphoreSlim(1, 1); | |||
public async Task ConnectAsync(TimeSpan timeout, CancellationToken cancellationToken) | |||
@@ -145,7 +145,7 @@ namespace MQTTnet.AspNetCore | |||
public async Task SendPacketAsync(MqttBasePacket packet, TimeSpan timeout, CancellationToken cancellationToken) | |||
{ | |||
var formatter = PacketFormatterAdapter; | |||
await _writerSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); | |||
try | |||
@@ -10,7 +10,7 @@ namespace MQTTnet.AspNetCore | |||
{ | |||
public class MqttConnectionHandler : ConnectionHandler, IMqttServerAdapter | |||
{ | |||
public Action<MqttServerAdapterClientAcceptedEventArgs> ClientAcceptedHandler { get; set; } | |||
public Func<IMqttChannelAdapter, Task> ClientHandler { get; set; } | |||
public override async Task OnConnectedAsync(ConnectionContext connection) | |||
{ | |||
@@ -25,10 +25,11 @@ namespace MQTTnet.AspNetCore | |||
var formatter = new MqttPacketFormatterAdapter(writer); | |||
using (var adapter = new MqttConnectionContext(formatter, connection)) | |||
{ | |||
var args = new MqttServerAdapterClientAcceptedEventArgs(adapter); | |||
ClientAcceptedHandler?.Invoke(args); | |||
await args.SessionTask.ConfigureAwait(false); | |||
var clientHandler = ClientHandler; | |||
if (clientHandler != null) | |||
{ | |||
await clientHandler(adapter).ConfigureAwait(false); | |||
} | |||
} | |||
} | |||
@@ -21,7 +21,7 @@ namespace MQTTnet.AspNetCore | |||
_logger = logger.CreateChildLogger(nameof(MqttTcpServerAdapter)); | |||
} | |||
public Action<MqttServerAdapterClientAcceptedEventArgs> ClientAcceptedHandler { get; set; } | |||
public Func<IMqttChannelAdapter, Task> ClientHandler { get; set; } | |||
public Task StartAsync(IMqttServerOptions options) | |||
{ | |||
@@ -43,17 +43,16 @@ namespace MQTTnet.AspNetCore | |||
var isSecureConnection = clientCertificate != null; | |||
clientCertificate?.Dispose(); | |||
var writer = new SpanBasedMqttPacketWriter(); | |||
var formatter = new MqttPacketFormatterAdapter(writer); | |||
var channel = new MqttWebSocketChannel(webSocket, endpoint, isSecureConnection); | |||
var channelAdapter = new MqttChannelAdapter(channel, formatter, _logger.CreateChildLogger(nameof(MqttWebSocketServerAdapter))); | |||
var eventArgs = new MqttServerAdapterClientAcceptedEventArgs(channelAdapter); | |||
ClientAcceptedHandler?.Invoke(eventArgs); | |||
if (eventArgs.SessionTask != null) | |||
var clientHandler = ClientHandler; | |||
if (clientHandler != null) | |||
{ | |||
await eventArgs.SessionTask.ConfigureAwait(false); | |||
var writer = new SpanBasedMqttPacketWriter(); | |||
var formatter = new MqttPacketFormatterAdapter(writer); | |||
var channel = new MqttWebSocketChannel(webSocket, endpoint, isSecureConnection); | |||
using (var channelAdapter = new MqttChannelAdapter(channel, formatter, _logger.CreateChildLogger(nameof(MqttWebSocketServerAdapter)))) | |||
{ | |||
await clientHandler(channelAdapter).ConfigureAwait(false); | |||
} | |||
} | |||
} | |||
@@ -0,0 +1,51 @@ | |||
using MQTTnet.Exceptions; | |||
using MQTTnet.Protocol; | |||
namespace MQTTnet | |||
{ | |||
public class TopicFilterBuilder | |||
{ | |||
private MqttQualityOfServiceLevel _qualityOfServiceLevel = MqttQualityOfServiceLevel.AtMostOnce; | |||
private string _topic; | |||
public TopicFilterBuilder WithTopic(string topic) | |||
{ | |||
_topic = topic; | |||
return this; | |||
} | |||
public TopicFilterBuilder WithQualityOfServiceLevel(MqttQualityOfServiceLevel qualityOfServiceLevel) | |||
{ | |||
_qualityOfServiceLevel = qualityOfServiceLevel; | |||
return this; | |||
} | |||
public TopicFilterBuilder WithAtLeastOnceQoS() | |||
{ | |||
_qualityOfServiceLevel = MqttQualityOfServiceLevel.AtLeastOnce; | |||
return this; | |||
} | |||
public TopicFilterBuilder WithAtMostOnceQoS() | |||
{ | |||
_qualityOfServiceLevel = MqttQualityOfServiceLevel.AtMostOnce; | |||
return this; | |||
} | |||
public TopicFilterBuilder WithExactlyOnceQoS() | |||
{ | |||
_qualityOfServiceLevel = MqttQualityOfServiceLevel.ExactlyOnce; | |||
return this; | |||
} | |||
public TopicFilter Build() | |||
{ | |||
if (string.IsNullOrEmpty(_topic)) | |||
{ | |||
throw new MqttProtocolViolationException("Topic is not set."); | |||
} | |||
return new TopicFilter { Topic = _topic, QualityOfServiceLevel = _qualityOfServiceLevel }; | |||
} | |||
} | |||
} |
@@ -45,6 +45,9 @@ | |||
/// </summary> | |||
public RetainedApplicationMessagesModel RetainedApplicationMessages { get; set; } = new RetainedApplicationMessagesModel(); | |||
/// <summary> | |||
/// Enables or disables the MQTTnet internal logging. | |||
/// </summary> | |||
public bool EnableDebugLogging { get; set; } = false; | |||
} | |||
} |
@@ -60,13 +60,13 @@ namespace MQTTnet.Server.Configuration | |||
{ | |||
if (IPv4 == "*") | |||
{ | |||
address = IPAddress.Parse("0.0.0.0"); | |||
address = IPAddress.Any; | |||
return true; | |||
} | |||
if (IPv4 == "localhost") | |||
{ | |||
address = IPAddress.Parse("127.0.0.1"); | |||
address = IPAddress.Loopback; | |||
return true; | |||
} | |||
@@ -81,10 +81,8 @@ namespace MQTTnet.Server.Configuration | |||
address = ip; | |||
return true; | |||
} | |||
else | |||
{ | |||
throw new System.Exception($"Could not parse IPv4 address: {IPv4}"); | |||
} | |||
throw new System.Exception($"Could not parse IPv4 address: {IPv4}"); | |||
} | |||
/// <summary> | |||
@@ -95,13 +93,13 @@ namespace MQTTnet.Server.Configuration | |||
{ | |||
if (IPv6 == "*") | |||
{ | |||
address = IPAddress.Parse("::"); | |||
address = IPAddress.IPv6Any; | |||
return true; | |||
} | |||
if (IPv6 == "localhost") | |||
{ | |||
address = IPAddress.Parse("::1"); | |||
address = IPAddress.IPv6Loopback; | |||
return true; | |||
} | |||
@@ -116,10 +114,8 @@ namespace MQTTnet.Server.Configuration | |||
address = ip; | |||
return true; | |||
} | |||
else | |||
{ | |||
throw new System.Exception($"Could not parse IPv6 address: {IPv6}"); | |||
} | |||
throw new System.Exception($"Could not parse IPv6 address: {IPv6}"); | |||
} | |||
} | |||
} |
@@ -152,6 +152,7 @@ namespace MQTTnet.Server.Mqtt | |||
if (_settings.TcpEndPoint.Enabled) | |||
{ | |||
options.WithDefaultEndpoint(); | |||
if (_settings.TcpEndPoint.TryReadIPv4(out var address4)) | |||
{ | |||
options.WithDefaultEndpointBoundIPAddress(address4); | |||
@@ -18,14 +18,14 @@ | |||
*/ | |||
"TcpEndPoint": { | |||
"Enabled": true, | |||
"IPv4": "localhost", | |||
"IPv6": "localhost", | |||
"IPv4": "*", | |||
"IPv6": "*", | |||
"Port": 1883 | |||
}, | |||
"EncryptedTcpEndPoint": { | |||
"Enabled": false, | |||
"IPv4": "localhost", | |||
"IPv6": "localhost", | |||
"IPv4": "*", | |||
"IPv6": "*", | |||
"Port": 8883, | |||
"CertificatePath": "/absolute/path/to/pfx" | |||
}, | |||
@@ -45,7 +45,7 @@ | |||
"Filename": "RetainedApplicationMessages.json", | |||
"WriteInterval": 10 // In seconds. | |||
}, | |||
"EnableDebugLogging": false | |||
"EnableDebugLogging": true | |||
}, | |||
"Logging": { | |||
"LogLevel": { | |||
@@ -6,7 +6,7 @@ namespace MQTTnet.Adapter | |||
{ | |||
public interface IMqttServerAdapter : IDisposable | |||
{ | |||
Action<MqttServerAdapterClientAcceptedEventArgs> ClientAcceptedHandler { get; set; } | |||
Func<IMqttChannelAdapter, Task> ClientHandler { get; set; } | |||
Task StartAsync(IMqttServerOptions options); | |||
Task StopAsync(); | |||
@@ -1,17 +0,0 @@ | |||
using System; | |||
using System.Threading.Tasks; | |||
namespace MQTTnet.Adapter | |||
{ | |||
public class MqttServerAdapterClientAcceptedEventArgs : EventArgs | |||
{ | |||
public MqttServerAdapterClientAcceptedEventArgs(IMqttChannelAdapter channelAdapter) | |||
{ | |||
ChannelAdapter = channelAdapter ?? throw new ArgumentNullException(nameof(channelAdapter)); | |||
} | |||
public IMqttChannelAdapter ChannelAdapter { get; } | |||
public Task SessionTask { get; set; } | |||
} | |||
} |
@@ -23,7 +23,7 @@ namespace MQTTnet.Implementations | |||
_logger = logger.CreateChildLogger(nameof(MqttTcpServerAdapter)); | |||
} | |||
public Action<MqttServerAdapterClientAcceptedEventArgs> ClientAcceptedHandler { get; set; } | |||
public Func<IMqttChannelAdapter, Task> ClientHandler { get; set; } | |||
public async Task StartAsync(IMqttServerOptions options) | |||
{ | |||
@@ -39,7 +39,7 @@ namespace MQTTnet.Implementations | |||
_listener.Control.NoDelay = options.DefaultEndpointOptions.NoDelay; | |||
_listener.Control.KeepAlive = true; | |||
_listener.Control.QualityOfService = SocketQualityOfService.LowLatency; | |||
_listener.ConnectionReceived += AcceptDefaultEndpointConnectionsAsync; | |||
_listener.ConnectionReceived += OnConnectionReceivedAsync; | |||
await _listener.BindServiceNameAsync(options.DefaultEndpointOptions.Port.ToString(), SocketProtectionLevel.PlainSocket); | |||
} | |||
@@ -54,30 +54,51 @@ namespace MQTTnet.Implementations | |||
{ | |||
if (_listener != null) | |||
{ | |||
_listener.ConnectionReceived -= AcceptDefaultEndpointConnectionsAsync; | |||
_listener.ConnectionReceived -= OnConnectionReceivedAsync; | |||
} | |||
_listener?.Dispose(); | |||
_listener = null; | |||
return Task.FromResult(0); | |||
} | |||
public void Dispose() | |||
{ | |||
StopAsync().GetAwaiter().GetResult(); | |||
_listener?.Dispose(); | |||
_listener = null; | |||
} | |||
private void AcceptDefaultEndpointConnectionsAsync(StreamSocketListener sender, StreamSocketListenerConnectionReceivedEventArgs args) | |||
private async void OnConnectionReceivedAsync(StreamSocketListener sender, StreamSocketListenerConnectionReceivedEventArgs args) | |||
{ | |||
try | |||
{ | |||
var clientAdapter = new MqttChannelAdapter(new MqttTcpChannel(args.Socket, _options), new MqttPacketFormatterAdapter(), _logger); | |||
ClientAcceptedHandler?.Invoke(new MqttServerAdapterClientAcceptedEventArgs(clientAdapter)); | |||
var clientHandler = ClientHandler; | |||
if (clientHandler != null) | |||
{ | |||
using (var clientAdapter = new MqttChannelAdapter(new MqttTcpChannel(args.Socket, _options), new MqttPacketFormatterAdapter(), _logger)) | |||
{ | |||
await clientHandler(clientAdapter).ConfigureAwait(false); | |||
} | |||
} | |||
} | |||
catch (Exception exception) | |||
{ | |||
_logger.Error(exception, "Error while accepting connection at default endpoint."); | |||
if (exception is ObjectDisposedException) | |||
{ | |||
// It can happen that the listener socket is accessed after the cancellation token is already set and the listener socket is disposed. | |||
return; | |||
} | |||
_logger.Error(exception, "Error while handling client connection."); | |||
} | |||
finally | |||
{ | |||
try | |||
{ | |||
args.Socket.Dispose(); | |||
} | |||
catch (Exception exception) | |||
{ | |||
_logger.Error(exception, "Error while cleaning up client connection"); | |||
} | |||
} | |||
} | |||
} | |||
@@ -26,7 +26,7 @@ namespace MQTTnet.Implementations | |||
_logger = logger.CreateChildLogger(nameof(MqttTcpServerAdapter)); | |||
} | |||
public Action<MqttServerAdapterClientAcceptedEventArgs> ClientAcceptedHandler { get; set; } | |||
public Func<IMqttChannelAdapter, Task> ClientHandler { get; set; } | |||
public Task StartAsync(IMqttServerOptions options) | |||
{ | |||
@@ -89,7 +89,7 @@ namespace MQTTnet.Implementations | |||
_cancellationTokenSource.Token, | |||
_logger) | |||
{ | |||
ClientAcceptedHandler = OnClientAccepted | |||
ClientHandler = OnClientAcceptedAsync | |||
}; | |||
listenerV4.Start(); | |||
@@ -105,7 +105,7 @@ namespace MQTTnet.Implementations | |||
_cancellationTokenSource.Token, | |||
_logger) | |||
{ | |||
ClientAcceptedHandler = OnClientAccepted | |||
ClientHandler = OnClientAcceptedAsync | |||
}; | |||
listenerV6.Start(); | |||
@@ -113,9 +113,15 @@ namespace MQTTnet.Implementations | |||
} | |||
} | |||
private void OnClientAccepted(MqttServerAdapterClientAcceptedEventArgs eventArgs) | |||
private Task OnClientAcceptedAsync(IMqttChannelAdapter channelAdapter) | |||
{ | |||
ClientAcceptedHandler?.Invoke(eventArgs); | |||
var clientHandler = ClientHandler; | |||
if (clientHandler == null) | |||
{ | |||
return Task.FromResult(0); | |||
} | |||
return clientHandler(channelAdapter); | |||
} | |||
} | |||
} |
@@ -43,7 +43,7 @@ namespace MQTTnet.Implementations | |||
} | |||
} | |||
public Action<MqttServerAdapterClientAcceptedEventArgs> ClientAcceptedHandler { get; set; } | |||
public Func<IMqttChannelAdapter, Task> ClientHandler { get; set; } | |||
public void Start() | |||
{ | |||
@@ -97,11 +97,14 @@ namespace MQTTnet.Implementations | |||
private async Task TryHandleClientConnectionAsync(Socket clientSocket) | |||
{ | |||
Stream stream = null; | |||
EndPoint remoteEndPoint = null; | |||
try | |||
{ | |||
remoteEndPoint = clientSocket.RemoteEndPoint; | |||
_logger.Verbose("Client '{0}' accepted by TCP listener '{1}, {2}'.", | |||
clientSocket.RemoteEndPoint, | |||
remoteEndPoint, | |||
_socket.LocalEndPoint, | |||
_addressFamily == AddressFamily.InterNetwork ? "ipv4" : "ipv6"); | |||
@@ -116,8 +119,14 @@ namespace MQTTnet.Implementations | |||
stream = sslStream; | |||
} | |||
var clientAdapter = new MqttChannelAdapter(new MqttTcpChannel(stream), new MqttPacketFormatterAdapter(), _logger); | |||
ClientAcceptedHandler?.Invoke(new MqttServerAdapterClientAcceptedEventArgs(clientAdapter)); | |||
var clientHandler = ClientHandler; | |||
if (clientHandler != null) | |||
{ | |||
using (var clientAdapter = new MqttChannelAdapter(new MqttTcpChannel(stream), new MqttPacketFormatterAdapter(), _logger)) | |||
{ | |||
await clientHandler(clientAdapter).ConfigureAwait(false); | |||
} | |||
} | |||
} | |||
catch (Exception exception) | |||
{ | |||
@@ -127,20 +136,29 @@ namespace MQTTnet.Implementations | |||
return; | |||
} | |||
if (exception is SocketException socketException && socketException.SocketErrorCode == SocketError.OperationAborted) | |||
if (exception is SocketException socketException && | |||
socketException.SocketErrorCode == SocketError.OperationAborted) | |||
{ | |||
return; | |||
} | |||
_logger.Error(exception, "Error while handling client connection."); | |||
} | |||
finally | |||
{ | |||
try | |||
{ | |||
// Dispose already allocated resources. | |||
stream?.Dispose(); | |||
clientSocket?.Dispose(); | |||
_logger.Verbose("Client '{0}' disconnected at TCP listener '{1}, {2}'.", | |||
remoteEndPoint, | |||
_socket.LocalEndPoint, | |||
_addressFamily == AddressFamily.InterNetwork ? "ipv4" : "ipv6"); | |||
} | |||
catch (Exception disposeException) | |||
{ | |||
_logger.Error(disposeException, "Error while cleanup of broken connection."); | |||
_logger.Error(disposeException, "Error while cleaning up client connection"); | |||
} | |||
} | |||
} | |||
@@ -1,5 +1,4 @@ | |||
using System; | |||
using System.Globalization; | |||
using System.Net; | |||
using System.Net.WebSockets; | |||
using System.Security.Cryptography.X509Certificates; | |||
@@ -27,12 +27,12 @@ namespace MQTTnet.Server | |||
private readonly IMqttNetChildLogger _logger; | |||
private readonly IMqttServerOptions _serverOptions; | |||
private Task<MqttClientDisconnectType> _packageReceiverTask; | |||
private readonly IMqttChannelAdapter _channelAdapter; | |||
private readonly IMqttDataConverter _dataConverter; | |||
private readonly string _endpoint; | |||
private readonly MqttConnectPacket _connectPacket; | |||
private Task<MqttClientDisconnectType> _packageReceiverTask; | |||
private DateTime _lastPacketReceivedTimestamp; | |||
private DateTime _lastNonKeepAlivePacketReceivedTimestamp; | |||
@@ -78,7 +78,7 @@ namespace MQTTnet.Server | |||
StopInternal(); | |||
var task = _packageReceiverTask; | |||
if (task != null && !task.IsCompleted) | |||
if (task != null) | |||
{ | |||
await task.ConfigureAwait(false); | |||
} | |||
@@ -103,13 +103,6 @@ namespace MQTTnet.Server | |||
status.BytesReceived = _channelAdapter.BytesReceived; | |||
} | |||
//public void ClearPendingApplicationMessages() | |||
//{ | |||
// Session.ApplicationMessagesQueue.Clear(); | |||
// //_applicationMessagesQueue.Clear(); | |||
//} | |||
public void Dispose() | |||
{ | |||
_cancellationToken.Dispose(); | |||
@@ -57,9 +57,9 @@ namespace MQTTnet.Server | |||
} | |||
} | |||
public Task HandleConnectionAsync(IMqttChannelAdapter clientAdapter) | |||
public Task HandleClientAsync(IMqttChannelAdapter clientAdapter) | |||
{ | |||
return HandleConnectionAsync(clientAdapter, _cancellationToken); | |||
return HandleClientAsync(clientAdapter, _cancellationToken); | |||
} | |||
public Task<IList<IMqttClientStatus>> GetClientStatusAsync() | |||
@@ -221,7 +221,7 @@ namespace MQTTnet.Server | |||
} | |||
} | |||
private async Task HandleConnectionAsync(IMqttChannelAdapter channelAdapter, CancellationToken cancellationToken) | |||
private async Task HandleClientAsync(IMqttChannelAdapter channelAdapter, CancellationToken cancellationToken) | |||
{ | |||
var disconnectType = MqttClientDisconnectType.NotClean; | |||
var clientId = string.Empty; | |||
@@ -376,10 +376,6 @@ namespace MQTTnet.Server | |||
{ | |||
_logger.Error(exception, "Error while disconnecting client channel."); | |||
} | |||
finally | |||
{ | |||
channelAdapter.Dispose(); | |||
} | |||
} | |||
} | |||
} |
@@ -127,7 +127,7 @@ namespace MQTTnet.Server | |||
foreach (var adapter in _adapters) | |||
{ | |||
adapter.ClientAcceptedHandler = OnClientAccepted; | |||
adapter.ClientHandler = OnHandleClient; | |||
await adapter.StartAsync(Options).ConfigureAwait(false); | |||
} | |||
@@ -155,7 +155,7 @@ namespace MQTTnet.Server | |||
foreach (var adapter in _adapters) | |||
{ | |||
adapter.ClientAcceptedHandler = null; | |||
adapter.ClientHandler = null; | |||
await adapter.StopAsync().ConfigureAwait(false); | |||
} | |||
@@ -184,9 +184,9 @@ namespace MQTTnet.Server | |||
return _retainedMessagesManager?.ClearMessagesAsync(); | |||
} | |||
private void OnClientAccepted(MqttServerAdapterClientAcceptedEventArgs eventArgs) | |||
private Task OnHandleClient(IMqttChannelAdapter channelAdapter) | |||
{ | |||
eventArgs.SessionTask = _clientSessionsManager.HandleConnectionAsync(eventArgs.ChannelAdapter); | |||
return _clientSessionsManager.HandleClientAsync(channelAdapter); | |||
} | |||
} | |||
} |
@@ -21,8 +21,16 @@ namespace MQTTnet.Benchmarks | |||
{ | |||
var factory = new MqttFactory(); | |||
var tcpServer = new MqttTcpServerAdapter(new MqttNetLogger().CreateChildLogger()); | |||
tcpServer.ClientAcceptedHandler += args => _serverChannel = (IMqttChannel)args.ChannelAdapter.GetType().GetField("_channel", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).GetValue(args.ChannelAdapter); | |||
tcpServer.ClientHandler += args => | |||
{ | |||
_serverChannel = | |||
(IMqttChannel)args.GetType().GetField("_channel", | |||
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance) | |||
.GetValue(args); | |||
return Task.CompletedTask; | |||
}; | |||
_mqttServer = factory.CreateMqttServer(new[] { tcpServer }, new MqttNetLogger()); | |||
var serverOptions = new MqttServerOptionsBuilder().Build(); | |||
@@ -1,61 +0,0 @@ | |||
using System; | |||
using System.Threading; | |||
using System.Threading.Tasks; | |||
using MQTTnet.Adapter; | |||
using MQTTnet.Client; | |||
using MQTTnet.Client.Options; | |||
using MQTTnet.Diagnostics; | |||
using MQTTnet.Server; | |||
namespace MQTTnet.Tests.Mockups | |||
{ | |||
public class TestMqttServerAdapter : IMqttServerAdapter | |||
{ | |||
public Action<MqttServerAdapterClientAcceptedEventArgs> ClientAcceptedHandler { get; set; } | |||
public async Task<IMqttClient> ConnectTestClient(string clientId, MqttApplicationMessage willMessage = null) | |||
{ | |||
var adapterA = new TestMqttCommunicationAdapter(); | |||
var adapterB = new TestMqttCommunicationAdapter(); | |||
adapterA.Partner = adapterB; | |||
adapterB.Partner = adapterA; | |||
var client = new MqttClient( | |||
new TestMqttCommunicationAdapterFactory(adapterA), | |||
new MqttNetLogger()); | |||
FireClientAcceptedEvent(adapterB); | |||
var options = new MqttClientOptions | |||
{ | |||
ClientId = clientId, | |||
WillMessage = willMessage, | |||
ChannelOptions = new MqttClientTcpOptions() | |||
}; | |||
await client.ConnectAsync(options); | |||
SpinWait.SpinUntil(() => client.IsConnected); | |||
return client; | |||
} | |||
private void FireClientAcceptedEvent(IMqttChannelAdapter adapter) | |||
{ | |||
ClientAcceptedHandler?.Invoke(new MqttServerAdapterClientAcceptedEventArgs(adapter)); | |||
} | |||
public Task StartAsync(IMqttServerOptions options) | |||
{ | |||
return Task.FromResult(0); | |||
} | |||
public Task StopAsync() | |||
{ | |||
return Task.FromResult(0); | |||
} | |||
public void Dispose() | |||
{ | |||
} | |||
} | |||
} |