Wrap COM exceptions, close client connection when server stops, process retained messages from server

This commit is contained in:
Christian Kratky
2017-11-16 00:28:56 +01:00
parent b956623234
commit 8de87c8772
10 changed files with 204 additions and 228 deletions
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using MQTTnet.Core.Channel;
@@ -14,10 +15,12 @@ namespace MQTTnet.Core.Adapter
{
public class MqttChannelCommunicationAdapter : IMqttCommunicationAdapter
{
private const uint ErrorOperationAborted = 0x800703E3;
private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1);
private readonly ILogger<MqttChannelCommunicationAdapter> _logger;
private readonly IMqttCommunicationChannel _channel;
public MqttChannelCommunicationAdapter(IMqttCommunicationChannel channel, IMqttPacketSerializer serializer, ILogger<MqttChannelCommunicationAdapter> logger)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
@@ -29,166 +32,87 @@ namespace MQTTnet.Core.Adapter
public async Task ConnectAsync(TimeSpan timeout)
{
try
{
await _channel.ConnectAsync().TimeoutAfter(timeout).ConfigureAwait(false);
}
catch (TaskCanceledException)
{
throw;
}
catch (OperationCanceledException)
{
throw;
}
catch (MqttCommunicationTimedOutException)
{
throw;
}
catch (MqttCommunicationException)
{
throw;
}
catch (Exception exception)
{
throw new MqttCommunicationException(exception);
}
await ExecuteAndWrapExceptionAsync(() => _channel.ConnectAsync().TimeoutAfter(timeout));
}
public async Task DisconnectAsync(TimeSpan timeout)
{
try
{
await _channel.DisconnectAsync().TimeoutAfter(timeout).ConfigureAwait(false);
}
catch (TaskCanceledException)
{
throw;
}
catch (OperationCanceledException)
{
throw;
}
catch (MqttCommunicationTimedOutException)
{
throw;
}
catch (MqttCommunicationException)
{
throw;
}
catch (Exception exception)
{
throw new MqttCommunicationException(exception);
}
await ExecuteAndWrapExceptionAsync(() => _channel.DisconnectAsync().TimeoutAfter(timeout));
}
public async Task SendPacketsAsync(TimeSpan timeout, CancellationToken cancellationToken, IEnumerable<MqttBasePacket> packets)
{
try
await ExecuteAndWrapExceptionAsync(async () =>
{
await _semaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
foreach (var packet in packets)
try
{
if (packet == null)
foreach (var packet in packets)
{
continue;
if (packet == null)
{
continue;
}
_logger.LogInformation("TX >>> {0} [Timeout={1}]", packet, timeout);
var writeBuffer = PacketSerializer.Serialize(packet);
await _channel.SendStream.WriteAsync(writeBuffer, 0, writeBuffer.Length, cancellationToken).ConfigureAwait(false);
}
_logger.LogInformation("TX >>> {0} [Timeout={1}]", packet, timeout);
var writeBuffer = PacketSerializer.Serialize(packet);
await _channel.SendStream.WriteAsync(writeBuffer, 0, writeBuffer.Length, cancellationToken).ConfigureAwait(false);
if (timeout > TimeSpan.Zero)
{
await _channel.SendStream.FlushAsync(cancellationToken).TimeoutAfter(timeout).ConfigureAwait(false);
}
else
{
await _channel.SendStream.FlushAsync(cancellationToken).ConfigureAwait(false);
}
}
if (timeout > TimeSpan.Zero)
finally
{
await _channel.SendStream.FlushAsync(cancellationToken).TimeoutAfter(timeout).ConfigureAwait(false);
_semaphore.Release();
}
else
{
await _channel.SendStream.FlushAsync(cancellationToken).ConfigureAwait(false);
}
}
catch (TaskCanceledException)
{
throw;
}
catch (OperationCanceledException)
{
throw;
}
catch (MqttCommunicationTimedOutException)
{
throw;
}
catch (MqttCommunicationException)
{
throw;
}
catch (Exception exception)
{
throw new MqttCommunicationException(exception);
}
finally
{
_semaphore.Release();
}
});
}
public async Task<MqttBasePacket> ReceivePacketAsync(TimeSpan timeout, CancellationToken cancellationToken)
{
ReceivedMqttPacket receivedMqttPacket = null;
try
MqttBasePacket packet = null;
await ExecuteAndWrapExceptionAsync(async () =>
{
if (timeout > TimeSpan.Zero)
ReceivedMqttPacket receivedMqttPacket = null;
try
{
receivedMqttPacket = await ReceiveAsync(_channel.ReceiveStream, cancellationToken).TimeoutAfter(timeout).ConfigureAwait(false);
}
else
{
receivedMqttPacket = await ReceiveAsync(_channel.ReceiveStream, cancellationToken).ConfigureAwait(false);
}
if (timeout > TimeSpan.Zero)
{
receivedMqttPacket = await ReceiveAsync(_channel.ReceiveStream, cancellationToken).TimeoutAfter(timeout).ConfigureAwait(false);
}
else
{
receivedMqttPacket = await ReceiveAsync(_channel.ReceiveStream, cancellationToken).ConfigureAwait(false);
}
if (receivedMqttPacket == null || cancellationToken.IsCancellationRequested)
{
throw new TaskCanceledException();
}
if (receivedMqttPacket == null || cancellationToken.IsCancellationRequested)
{
throw new TaskCanceledException();
}
var packet = PacketSerializer.Deserialize(receivedMqttPacket);
if (packet == null)
{
throw new MqttProtocolViolationException("Received malformed packet.");
}
packet = PacketSerializer.Deserialize(receivedMqttPacket);
if (packet == null)
{
throw new MqttProtocolViolationException("Received malformed packet.");
}
_logger.LogInformation("RX <<< {0}", packet);
return packet;
}
catch (TaskCanceledException)
{
throw;
}
catch (OperationCanceledException)
{
throw;
}
catch (MqttCommunicationTimedOutException)
{
throw;
}
catch (MqttCommunicationException)
{
throw;
}
catch (Exception exception)
{
throw new MqttCommunicationException(exception);
}
finally
{
receivedMqttPacket?.Dispose();
}
_logger.LogInformation("RX <<< {0}", packet);
}
finally
{
receivedMqttPacket?.Dispose();
}
});
return packet;
}
private static async Task<ReceivedMqttPacket> ReceiveAsync(Stream stream, CancellationToken cancellationToken)
@@ -215,5 +139,42 @@ namespace MQTTnet.Core.Adapter
return new ReceivedMqttPacket(header, new MemoryStream(body, 0, body.Length));
}
private static async Task ExecuteAndWrapExceptionAsync(Func<Task> action)
{
try
{
await action().ConfigureAwait(false);
}
catch (TaskCanceledException)
{
throw;
}
catch (OperationCanceledException)
{
throw;
}
catch (MqttCommunicationTimedOutException)
{
throw;
}
catch (MqttCommunicationException)
{
throw;
}
catch (COMException comException)
{
if ((uint)comException.HResult == ErrorOperationAborted)
{
throw new OperationCanceledException();
}
throw new MqttCommunicationException(comException);
}
catch (Exception exception)
{
throw new MqttCommunicationException(exception);
}
}
}
}