mirror of
https://github.com/dotnet/MQTTnet.git
synced 2026-10-28 01:02:37 +08:00
Make internal message of server async.
This commit is contained in:
@@ -20,12 +20,17 @@ namespace MQTTnet.AspNetCore
|
|||||||
}
|
}
|
||||||
|
|
||||||
public string Endpoint => Connection.ConnectionId;
|
public string Endpoint => Connection.ConnectionId;
|
||||||
public bool IsSecureConnection => false; // TODO: Fix detection.
|
public bool IsSecureConnection => false; // TODO: Fix detection (WS vs. WSS).
|
||||||
|
|
||||||
public ConnectionContext Connection { get; }
|
public ConnectionContext Connection { get; }
|
||||||
public MqttPacketFormatterAdapter PacketFormatterAdapter { get; }
|
public MqttPacketFormatterAdapter PacketFormatterAdapter { get; }
|
||||||
public event EventHandler ReadingPacketStarted;
|
|
||||||
public event EventHandler ReadingPacketCompleted;
|
|
||||||
|
|
||||||
|
public long BytesSent { get; } // TODO: Fix calculation.
|
||||||
|
public long BytesReceived { get; } // TODO: Fix calculation.
|
||||||
|
|
||||||
|
public Action ReadingPacketStartedCallback { get; set; }
|
||||||
|
public Action ReadingPacketCompletedCallback { get; set; }
|
||||||
|
|
||||||
private readonly SemaphoreSlim _writerSemaphore = new SemaphoreSlim(1, 1);
|
private readonly SemaphoreSlim _writerSemaphore = new SemaphoreSlim(1, 1);
|
||||||
|
|
||||||
public Task ConnectAsync(TimeSpan timeout, CancellationToken cancellationToken)
|
public Task ConnectAsync(TimeSpan timeout, CancellationToken cancellationToken)
|
||||||
@@ -34,6 +39,7 @@ namespace MQTTnet.AspNetCore
|
|||||||
{
|
{
|
||||||
return tcp.StartAsync();
|
return tcp.StartAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,7 +86,7 @@ namespace MQTTnet.AspNetCore
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// we did receive something but the message is not yet complete
|
// we did receive something but the message is not yet complete
|
||||||
ReadingPacketStarted?.Invoke(this, EventArgs.Empty);
|
ReadingPacketStartedCallback?.Invoke();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (readResult.IsCompleted)
|
else if (readResult.IsCompleted)
|
||||||
@@ -99,7 +105,7 @@ namespace MQTTnet.AspNetCore
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
ReadingPacketCompleted?.Invoke(this, EventArgs.Empty);
|
ReadingPacketCompletedCallback?.Invoke();
|
||||||
}
|
}
|
||||||
|
|
||||||
cancellationToken.ThrowIfCancellationRequested();
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|||||||
@@ -13,10 +13,14 @@ namespace MQTTnet.Adapter
|
|||||||
bool IsSecureConnection { get; }
|
bool IsSecureConnection { get; }
|
||||||
|
|
||||||
MqttPacketFormatterAdapter PacketFormatterAdapter { get; }
|
MqttPacketFormatterAdapter PacketFormatterAdapter { get; }
|
||||||
|
|
||||||
event EventHandler ReadingPacketStarted;
|
|
||||||
|
|
||||||
event EventHandler ReadingPacketCompleted;
|
long BytesSent { get; }
|
||||||
|
|
||||||
|
long BytesReceived { get; }
|
||||||
|
|
||||||
|
Action ReadingPacketStartedCallback { get; set; }
|
||||||
|
|
||||||
|
Action ReadingPacketCompletedCallback { get; set; }
|
||||||
|
|
||||||
Task ConnectAsync(TimeSpan timeout, CancellationToken cancellationToken);
|
Task ConnectAsync(TimeSpan timeout, CancellationToken cancellationToken);
|
||||||
|
|
||||||
|
|||||||
@@ -25,16 +25,19 @@ namespace MQTTnet.Adapter
|
|||||||
private readonly MqttPacketReader _packetReader;
|
private readonly MqttPacketReader _packetReader;
|
||||||
|
|
||||||
private readonly byte[] _fixedHeaderBuffer = new byte[2];
|
private readonly byte[] _fixedHeaderBuffer = new byte[2];
|
||||||
|
|
||||||
private bool _isDisposed;
|
private bool _isDisposed;
|
||||||
|
|
||||||
|
private long _bytesReceived;
|
||||||
|
private long _bytesSent;
|
||||||
|
|
||||||
public MqttChannelAdapter(IMqttChannel channel, MqttPacketFormatterAdapter packetFormatterAdapter, IMqttNetChildLogger logger)
|
public MqttChannelAdapter(IMqttChannel channel, MqttPacketFormatterAdapter packetFormatterAdapter, IMqttNetChildLogger logger)
|
||||||
{
|
{
|
||||||
if (logger == null) throw new ArgumentNullException(nameof(logger));
|
if (logger == null) throw new ArgumentNullException(nameof(logger));
|
||||||
|
|
||||||
_channel = channel ?? throw new ArgumentNullException(nameof(channel));
|
_channel = channel ?? throw new ArgumentNullException(nameof(channel));
|
||||||
PacketFormatterAdapter = packetFormatterAdapter ?? throw new ArgumentNullException(nameof(packetFormatterAdapter));
|
PacketFormatterAdapter = packetFormatterAdapter ?? throw new ArgumentNullException(nameof(packetFormatterAdapter));
|
||||||
|
|
||||||
_packetReader = new MqttPacketReader(_channel);
|
_packetReader = new MqttPacketReader(_channel);
|
||||||
|
|
||||||
_logger = logger.CreateChildLogger(nameof(MqttChannelAdapter));
|
_logger = logger.CreateChildLogger(nameof(MqttChannelAdapter));
|
||||||
@@ -46,9 +49,12 @@ namespace MQTTnet.Adapter
|
|||||||
|
|
||||||
public MqttPacketFormatterAdapter PacketFormatterAdapter { get; }
|
public MqttPacketFormatterAdapter PacketFormatterAdapter { get; }
|
||||||
|
|
||||||
public event EventHandler ReadingPacketStarted;
|
public long BytesSent => Interlocked.Read(ref _bytesSent);
|
||||||
public event EventHandler ReadingPacketCompleted;
|
public long BytesReceived => Interlocked.Read(ref _bytesReceived);
|
||||||
|
|
||||||
|
public Action ReadingPacketStartedCallback { get; set; }
|
||||||
|
public Action ReadingPacketCompletedCallback { get; set; }
|
||||||
|
|
||||||
public async Task ConnectAsync(TimeSpan timeout, CancellationToken cancellationToken)
|
public async Task ConnectAsync(TimeSpan timeout, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
ThrowIfDisposed();
|
ThrowIfDisposed();
|
||||||
@@ -62,7 +68,7 @@ namespace MQTTnet.Adapter
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
await MqttTaskTimeout.WaitAsync(t => _channel.ConnectAsync(t), timeout, cancellationToken).ConfigureAwait(false);
|
await MqttTaskTimeout.WaitAsync(t => _channel.ConnectAsync(t), timeout, cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception exception)
|
catch (Exception exception)
|
||||||
{
|
{
|
||||||
@@ -101,7 +107,7 @@ namespace MQTTnet.Adapter
|
|||||||
WrapException(exception);
|
WrapException(exception);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task SendPacketAsync(MqttBasePacket packet, TimeSpan timeout, CancellationToken cancellationToken)
|
public async Task SendPacketAsync(MqttBasePacket packet, TimeSpan timeout, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
await _writerSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
|
await _writerSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
|
||||||
@@ -118,7 +124,9 @@ namespace MQTTnet.Adapter
|
|||||||
await MqttTaskTimeout.WaitAsync(
|
await MqttTaskTimeout.WaitAsync(
|
||||||
t => _channel.WriteAsync(packetData.Array, packetData.Offset, packetData.Count, t), timeout, cancellationToken).ConfigureAwait(false);
|
t => _channel.WriteAsync(packetData.Array, packetData.Offset, packetData.Count, t), timeout, cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Interlocked.Add(ref _bytesReceived, packetData.Count);
|
||||||
|
|
||||||
PacketFormatterAdapter.FreeBuffer();
|
PacketFormatterAdapter.FreeBuffer();
|
||||||
|
|
||||||
_logger.Verbose("TX ({0} bytes) >>> {1}", packetData.Count, packet);
|
_logger.Verbose("TX ({0} bytes) >>> {1}", packetData.Count, packet);
|
||||||
@@ -159,7 +167,9 @@ namespace MQTTnet.Adapter
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!PacketFormatterAdapter.ProtocolVersion.HasValue)
|
Interlocked.Add(ref _bytesSent, receivedMqttPacket.TotalLength);
|
||||||
|
|
||||||
|
if (PacketFormatterAdapter.ProtocolVersion == MqttProtocolVersion.Unknown)
|
||||||
{
|
{
|
||||||
PacketFormatterAdapter.DetectProtocolVersion(receivedMqttPacket);
|
PacketFormatterAdapter.DetectProtocolVersion(receivedMqttPacket);
|
||||||
}
|
}
|
||||||
@@ -190,10 +200,21 @@ namespace MQTTnet.Adapter
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void ResetStatistics()
|
||||||
|
{
|
||||||
|
Interlocked.Exchange(ref _bytesReceived, 0L);
|
||||||
|
Interlocked.Exchange(ref _bytesSent, 0L);
|
||||||
|
}
|
||||||
|
|
||||||
private async Task<ReceivedMqttPacket> ReceiveAsync(CancellationToken cancellationToken)
|
private async Task<ReceivedMqttPacket> ReceiveAsync(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var readFixedHeaderResult = await _packetReader.ReadFixedHeaderAsync(_fixedHeaderBuffer, cancellationToken).ConfigureAwait(false);
|
var readFixedHeaderResult = await _packetReader.ReadFixedHeaderAsync(_fixedHeaderBuffer, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
|
if (cancellationToken.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (readFixedHeaderResult.ConnectionClosed)
|
if (readFixedHeaderResult.ConnectionClosed)
|
||||||
@@ -201,7 +222,7 @@ namespace MQTTnet.Adapter
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReadingPacketStarted?.Invoke(this, EventArgs.Empty);
|
ReadingPacketStartedCallback?.Invoke();
|
||||||
|
|
||||||
var fixedHeader = readFixedHeaderResult.FixedHeader;
|
var fixedHeader = readFixedHeaderResult.FixedHeader;
|
||||||
if (fixedHeader.RemainingLength == 0)
|
if (fixedHeader.RemainingLength == 0)
|
||||||
@@ -221,13 +242,7 @@ namespace MQTTnet.Adapter
|
|||||||
chunkSize = bytesLeft;
|
chunkSize = bytesLeft;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if WINDOWS_UWP
|
var readBytes = await _channel.ReadAsync(body, bodyOffset, chunkSize, cancellationToken).ConfigureAwait(false);
|
||||||
var readBytes = await _channel.ReadAsync(body, bodyOffset, (int)chunkSize, cancellationToken).ConfigureAwait(false);
|
|
||||||
#else
|
|
||||||
// async/await is not used to avoid the overhead of context switches. We assume that the remaining data
|
|
||||||
// has been sent from the sender directly after the initial bytes.
|
|
||||||
var readBytes = _channel.ReadAsync(body, bodyOffset, chunkSize, cancellationToken).ConfigureAwait(false).GetAwaiter().GetResult();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (cancellationToken.IsCancellationRequested)
|
if (cancellationToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
@@ -238,7 +253,7 @@ namespace MQTTnet.Adapter
|
|||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
bodyOffset += readBytes;
|
bodyOffset += readBytes;
|
||||||
} while (bodyOffset < body.Length);
|
} while (bodyOffset < body.Length);
|
||||||
|
|
||||||
@@ -247,7 +262,7 @@ namespace MQTTnet.Adapter
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
ReadingPacketCompleted?.Invoke(this, EventArgs.Empty);
|
ReadingPacketCompletedCallback?.Invoke();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ namespace MQTTnet.Formatter
|
|||||||
UseProtocolVersion(protocolVersion);
|
UseProtocolVersion(protocolVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
public MqttProtocolVersion? ProtocolVersion { get; private set; }
|
public MqttProtocolVersion ProtocolVersion { get; private set; }
|
||||||
|
|
||||||
public IMqttDataConverter DataConverter
|
public IMqttDataConverter DataConverter
|
||||||
{
|
{
|
||||||
@@ -64,6 +64,11 @@ namespace MQTTnet.Formatter
|
|||||||
|
|
||||||
private void UseProtocolVersion(MqttProtocolVersion protocolVersion)
|
private void UseProtocolVersion(MqttProtocolVersion protocolVersion)
|
||||||
{
|
{
|
||||||
|
if (protocolVersion == MqttProtocolVersion.Unknown)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("MQTT protocol version is invalid.");
|
||||||
|
}
|
||||||
|
|
||||||
ProtocolVersion = protocolVersion;
|
ProtocolVersion = protocolVersion;
|
||||||
|
|
||||||
switch (protocolVersion)
|
switch (protocolVersion)
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ using System.Threading;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using MQTTnet.Channel;
|
using MQTTnet.Channel;
|
||||||
using MQTTnet.Exceptions;
|
using MQTTnet.Exceptions;
|
||||||
using MQTTnet.Internal;
|
|
||||||
|
|
||||||
namespace MQTTnet.Formatter
|
namespace MQTTnet.Formatter
|
||||||
{
|
{
|
||||||
@@ -31,8 +30,11 @@ namespace MQTTnet.Formatter
|
|||||||
{
|
{
|
||||||
var bytesRead = await _channel.ReadAsync(buffer, totalBytesRead, buffer.Length - totalBytesRead, cancellationToken).ConfigureAwait(false);
|
var bytesRead = await _channel.ReadAsync(buffer, totalBytesRead, buffer.Length - totalBytesRead, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
cancellationToken.ThrowIfCancellationRequested();
|
if (cancellationToken.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
if (bytesRead == 0)
|
if (bytesRead == 0)
|
||||||
{
|
{
|
||||||
return new ReadFixedHeaderResult
|
return new ReadFixedHeaderResult
|
||||||
@@ -100,13 +102,19 @@ namespace MQTTnet.Formatter
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
var buffer = ReadByte(cancellationToken);
|
var readCount = _channel.ReadAsync(_singleByteBuffer, 0, 1, cancellationToken).GetAwaiter().GetResult();
|
||||||
if (!buffer.HasValue)
|
|
||||||
|
if (cancellationToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
encodedByte = buffer.Value;
|
if (readCount == 0)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
encodedByte = _singleByteBuffer[0];
|
||||||
|
|
||||||
value += (encodedByte & 127) * multiplier;
|
value += (encodedByte & 127) * multiplier;
|
||||||
multiplier *= 128;
|
multiplier *= 128;
|
||||||
@@ -114,26 +122,8 @@ namespace MQTTnet.Formatter
|
|||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte? ReadByte(CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
var readCount = _channel.ReadAsync(_singleByteBuffer, 0, 1, cancellationToken).ConfigureAwait(false).GetAwaiter().GetResult();
|
|
||||||
|
|
||||||
if (cancellationToken.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (readCount == 0)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return _singleByteBuffer[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
private async Task<int?> ReadBodyLengthAsync(byte initialEncodedByte, CancellationToken cancellationToken)
|
private async Task<int?> ReadBodyLengthAsync(byte initialEncodedByte, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var offset = 0;
|
var offset = 0;
|
||||||
@@ -154,13 +144,19 @@ namespace MQTTnet.Formatter
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
var buffer = await ReadByteAsync(cancellationToken).ConfigureAwait(false);
|
var readCount = await _channel.ReadAsync(_singleByteBuffer, 0, 1, cancellationToken).ConfigureAwait(false);
|
||||||
if (!buffer.HasValue)
|
|
||||||
|
if (cancellationToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
encodedByte = buffer.Value;
|
if (readCount == 0)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
encodedByte = _singleByteBuffer[0];
|
||||||
|
|
||||||
value += (encodedByte & 127) * multiplier;
|
value += (encodedByte & 127) * multiplier;
|
||||||
multiplier *= 128;
|
multiplier *= 128;
|
||||||
@@ -168,24 +164,6 @@ namespace MQTTnet.Formatter
|
|||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<byte?> ReadByteAsync(CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
var readCount = await _channel.ReadAsync(_singleByteBuffer, 0, 1, cancellationToken).ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (cancellationToken.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (readCount == 0)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return _singleByteBuffer[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
{
|
{
|
||||||
public enum MqttProtocolVersion
|
public enum MqttProtocolVersion
|
||||||
{
|
{
|
||||||
|
Unknown = 0,
|
||||||
|
|
||||||
V310 = 3,
|
V310 = 3,
|
||||||
V311 = 4,
|
V311 = 4,
|
||||||
V500 = 5
|
V500 = 5
|
||||||
|
|||||||
@@ -8,7 +8,10 @@ namespace MQTTnet.Internal
|
|||||||
public sealed class AsyncQueue<TItem> : IDisposable
|
public sealed class AsyncQueue<TItem> : IDisposable
|
||||||
{
|
{
|
||||||
private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(0);
|
private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(0);
|
||||||
private readonly ConcurrentQueue<TItem> _queue = new ConcurrentQueue<TItem>();
|
|
||||||
|
private ConcurrentQueue<TItem> _queue = new ConcurrentQueue<TItem>();
|
||||||
|
|
||||||
|
public int Count => _queue.Count;
|
||||||
|
|
||||||
public void Enqueue(TItem item)
|
public void Enqueue(TItem item)
|
||||||
{
|
{
|
||||||
@@ -16,9 +19,9 @@ namespace MQTTnet.Internal
|
|||||||
_semaphore.Release();
|
_semaphore.Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<TItem> DequeueAsync(CancellationToken cancellationToken)
|
public async Task<AsyncQueueDequeueResult<TItem>> TryDequeueAsync(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
while (true)
|
while (!cancellationToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
await _semaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
|
await _semaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
@@ -26,9 +29,26 @@ namespace MQTTnet.Internal
|
|||||||
|
|
||||||
if (_queue.TryDequeue(out var item))
|
if (_queue.TryDequeue(out var item))
|
||||||
{
|
{
|
||||||
return item;
|
return new AsyncQueueDequeueResult<TItem>(true, item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return new AsyncQueueDequeueResult<TItem>(false, default(TItem));
|
||||||
|
}
|
||||||
|
|
||||||
|
public AsyncQueueDequeueResult<TItem> TryDequeue()
|
||||||
|
{
|
||||||
|
if (_queue.TryDequeue(out var item))
|
||||||
|
{
|
||||||
|
return new AsyncQueueDequeueResult<TItem>(true, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new AsyncQueueDequeueResult<TItem>(false, default(TItem));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
Interlocked.Exchange(ref _queue, new ConcurrentQueue<TItem>());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
namespace MQTTnet.Internal
|
||||||
|
{
|
||||||
|
public class AsyncQueueDequeueResult<TItem>
|
||||||
|
{
|
||||||
|
public AsyncQueueDequeueResult(bool isSuccess, TItem item)
|
||||||
|
{
|
||||||
|
IsSuccess = isSuccess;
|
||||||
|
Item = item;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsSuccess { get; }
|
||||||
|
|
||||||
|
public TItem Item { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -34,8 +34,10 @@ namespace MQTTnet.Server
|
|||||||
private readonly MqttConnectPacket _connectPacket;
|
private readonly MqttConnectPacket _connectPacket;
|
||||||
|
|
||||||
private DateTime _lastPacketReceivedTimestamp;
|
private DateTime _lastPacketReceivedTimestamp;
|
||||||
|
private DateTime _lastNonKeepAlivePacketReceivedTimestamp;
|
||||||
|
|
||||||
private long _receivedPacketsCount;
|
private long _receivedPacketsCount;
|
||||||
private long _sentPacketsCount;
|
private long _sentPacketsCount = 1; // Start with 1 because the CONNECT packet is not counted anywhere.
|
||||||
private long _receivedApplicationMessagesCount;
|
private long _receivedApplicationMessagesCount;
|
||||||
private long _sentApplicationMessagesCount;
|
private long _sentApplicationMessagesCount;
|
||||||
|
|
||||||
@@ -64,6 +66,7 @@ namespace MQTTnet.Server
|
|||||||
_keepAliveMonitor = new MqttClientKeepAliveMonitor(this, _logger);
|
_keepAliveMonitor = new MqttClientKeepAliveMonitor(this, _logger);
|
||||||
|
|
||||||
_lastPacketReceivedTimestamp = DateTime.UtcNow;
|
_lastPacketReceivedTimestamp = DateTime.UtcNow;
|
||||||
|
_lastNonKeepAlivePacketReceivedTimestamp = _lastPacketReceivedTimestamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string ClientId => _connectPacket.ClientId;
|
public string ClientId => _connectPacket.ClientId;
|
||||||
@@ -85,7 +88,7 @@ namespace MQTTnet.Server
|
|||||||
{
|
{
|
||||||
status.ClientId = ClientId;
|
status.ClientId = ClientId;
|
||||||
status.Endpoint = _endpoint;
|
status.Endpoint = _endpoint;
|
||||||
status.ProtocolVersion = _channelAdapter.PacketFormatterAdapter.ProtocolVersion.Value;
|
status.ProtocolVersion = _channelAdapter.PacketFormatterAdapter.ProtocolVersion;
|
||||||
|
|
||||||
status.ReceivedApplicationMessagesCount = Interlocked.Read(ref _receivedApplicationMessagesCount);
|
status.ReceivedApplicationMessagesCount = Interlocked.Read(ref _receivedApplicationMessagesCount);
|
||||||
status.SentApplicationMessagesCount = Interlocked.Read(ref _sentApplicationMessagesCount);
|
status.SentApplicationMessagesCount = Interlocked.Read(ref _sentApplicationMessagesCount);
|
||||||
@@ -94,8 +97,10 @@ namespace MQTTnet.Server
|
|||||||
status.SentPacketsCount = Interlocked.Read(ref _sentPacketsCount);
|
status.SentPacketsCount = Interlocked.Read(ref _sentPacketsCount);
|
||||||
|
|
||||||
status.LastPacketReceivedTimestamp = _lastPacketReceivedTimestamp;
|
status.LastPacketReceivedTimestamp = _lastPacketReceivedTimestamp;
|
||||||
|
status.LastNonKeepAlivePacketReceivedTimestamp = _lastNonKeepAlivePacketReceivedTimestamp;
|
||||||
|
|
||||||
//status.LastNonKeepAlivePacketReceived = _keepAliveMonitor.LastNonKeepAlivePacketReceived;
|
status.BytesSent = _channelAdapter.BytesSent;
|
||||||
|
status.BytesReceived = _channelAdapter.BytesReceived;
|
||||||
}
|
}
|
||||||
|
|
||||||
//public void ClearPendingApplicationMessages()
|
//public void ClearPendingApplicationMessages()
|
||||||
@@ -131,10 +136,9 @@ namespace MQTTnet.Server
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
_logger.Info("Client '{0}': Session started.", ClientId);
|
_logger.Info("Client '{0}': Session started.", ClientId);
|
||||||
//_eventDispatcher.OnClientConnected(ClientId);
|
|
||||||
|
_channelAdapter.ReadingPacketStartedCallback = OnAdapterReadingPacketStarted;
|
||||||
_channelAdapter.ReadingPacketStarted += OnAdapterReadingPacketStarted;
|
_channelAdapter.ReadingPacketCompletedCallback = OnAdapterReadingPacketCompleted;
|
||||||
_channelAdapter.ReadingPacketCompleted += OnAdapterReadingPacketCompleted;
|
|
||||||
|
|
||||||
Session.WillMessage = _connectPacket.WillMessage;
|
Session.WillMessage = _connectPacket.WillMessage;
|
||||||
|
|
||||||
@@ -166,7 +170,12 @@ namespace MQTTnet.Server
|
|||||||
|
|
||||||
Interlocked.Increment(ref _sentPacketsCount);
|
Interlocked.Increment(ref _sentPacketsCount);
|
||||||
_lastPacketReceivedTimestamp = DateTime.UtcNow;
|
_lastPacketReceivedTimestamp = DateTime.UtcNow;
|
||||||
|
|
||||||
|
if (!(packet is MqttPingReqPacket || packet is MqttPingRespPacket))
|
||||||
|
{
|
||||||
|
_lastNonKeepAlivePacketReceivedTimestamp = _lastPacketReceivedTimestamp;
|
||||||
|
}
|
||||||
|
|
||||||
_keepAliveMonitor.PacketReceived();
|
_keepAliveMonitor.PacketReceived();
|
||||||
|
|
||||||
if (packet is MqttPublishPacket publishPacket)
|
if (packet is MqttPublishPacket publishPacket)
|
||||||
@@ -243,12 +252,11 @@ namespace MQTTnet.Server
|
|||||||
|
|
||||||
_packetDispatcher.Reset();
|
_packetDispatcher.Reset();
|
||||||
|
|
||||||
_channelAdapter.ReadingPacketStarted -= OnAdapterReadingPacketStarted;
|
_channelAdapter.ReadingPacketStartedCallback = null;
|
||||||
_channelAdapter.ReadingPacketCompleted -= OnAdapterReadingPacketCompleted;
|
_channelAdapter.ReadingPacketCompletedCallback = null;
|
||||||
|
|
||||||
_logger.Info("Client '{0}': Session stopped.", ClientId);
|
_logger.Info("Client '{0}': Session stopped.", ClientId);
|
||||||
//_eventDispatcher.OnClientDisconnected(ClientId);
|
|
||||||
|
|
||||||
_packageReceiverTask = null;
|
_packageReceiverTask = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -376,7 +384,7 @@ namespace MQTTnet.Server
|
|||||||
|
|
||||||
private async Task SendPendingPacketsAsync(CancellationToken cancellationToken)
|
private async Task SendPendingPacketsAsync(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
MqttPendingApplicationMessage queuedApplicationMessage = null;
|
MqttQueuedApplicationMessage queuedApplicationMessage = null;
|
||||||
MqttPublishPacket publishPacket = null;
|
MqttPublishPacket publishPacket = null;
|
||||||
|
|
||||||
try
|
try
|
||||||
@@ -501,12 +509,12 @@ namespace MQTTnet.Server
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnAdapterReadingPacketCompleted(object sender, EventArgs e)
|
private void OnAdapterReadingPacketCompleted()
|
||||||
{
|
{
|
||||||
_keepAliveMonitor?.Resume();
|
_keepAliveMonitor?.Resume();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnAdapterReadingPacketStarted(object sender, EventArgs e)
|
private void OnAdapterReadingPacketStarted()
|
||||||
{
|
{
|
||||||
_keepAliveMonitor?.Pause();
|
_keepAliveMonitor?.Pause();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ using System.Diagnostics;
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using MQTTnet.Diagnostics;
|
using MQTTnet.Diagnostics;
|
||||||
using MQTTnet.Packets;
|
|
||||||
|
|
||||||
namespace MQTTnet.Server
|
namespace MQTTnet.Server
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,54 +1,29 @@
|
|||||||
using MQTTnet.Internal;
|
using MQTTnet.Internal;
|
||||||
using MQTTnet.Protocol;
|
using MQTTnet.Protocol;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace MQTTnet.Server
|
namespace MQTTnet.Server
|
||||||
{
|
{
|
||||||
public class MqttPendingApplicationMessage
|
|
||||||
{
|
|
||||||
public MqttApplicationMessage ApplicationMessage { get; set; }
|
|
||||||
|
|
||||||
public string SenderClientId { get; set; }
|
|
||||||
|
|
||||||
public bool IsRetainedMessage { get; set; }
|
|
||||||
|
|
||||||
public MqttQualityOfServiceLevel QualityOfServiceLevel { get; set; }
|
|
||||||
|
|
||||||
public bool IsDuplicate { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class MqttClientSessionApplicationMessagesQueue : IDisposable
|
public class MqttClientSessionApplicationMessagesQueue : IDisposable
|
||||||
{
|
{
|
||||||
private readonly Queue<MqttPendingApplicationMessage> _messageQueue = new Queue<MqttPendingApplicationMessage>();
|
private readonly AsyncQueue<MqttQueuedApplicationMessage> _messageQueue = new AsyncQueue<MqttQueuedApplicationMessage>();
|
||||||
private readonly AsyncAutoResetEvent _messageQueueLock = new AsyncAutoResetEvent();
|
|
||||||
|
|
||||||
private readonly IMqttServerOptions _options;
|
private readonly IMqttServerOptions _options;
|
||||||
|
|
||||||
public MqttClientSessionApplicationMessagesQueue(IMqttServerOptions options)
|
public MqttClientSessionApplicationMessagesQueue(IMqttServerOptions options)
|
||||||
{
|
{
|
||||||
_options = options ?? throw new ArgumentNullException(nameof(options));
|
_options = options ?? throw new ArgumentNullException(nameof(options));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int Count
|
public int Count => _messageQueue.Count;
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
lock (_messageQueue)
|
|
||||||
{
|
|
||||||
return _messageQueue.Count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Enqueue(MqttApplicationMessage applicationMessage, string senderClientId, MqttQualityOfServiceLevel qualityOfServiceLevel, bool isRetainedMessage)
|
public void Enqueue(MqttApplicationMessage applicationMessage, string senderClientId, MqttQualityOfServiceLevel qualityOfServiceLevel, bool isRetainedMessage)
|
||||||
{
|
{
|
||||||
if (applicationMessage == null) throw new ArgumentNullException(nameof(applicationMessage));
|
if (applicationMessage == null) throw new ArgumentNullException(nameof(applicationMessage));
|
||||||
|
|
||||||
Enqueue(new MqttPendingApplicationMessage
|
Enqueue(new MqttQueuedApplicationMessage
|
||||||
{
|
{
|
||||||
ApplicationMessage = applicationMessage,
|
ApplicationMessage = applicationMessage,
|
||||||
SenderClientId = senderClientId,
|
SenderClientId = senderClientId,
|
||||||
@@ -59,39 +34,23 @@ namespace MQTTnet.Server
|
|||||||
|
|
||||||
public void Clear()
|
public void Clear()
|
||||||
{
|
{
|
||||||
lock (_messageQueue)
|
_messageQueue.Clear();
|
||||||
{
|
|
||||||
_messageQueue.Clear();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public async Task<MqttQueuedApplicationMessage> TakeAsync(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
}
|
var dequeueResult = await _messageQueue.TryDequeueAsync(cancellationToken).ConfigureAwait(false);
|
||||||
|
if (!dequeueResult.IsSuccess)
|
||||||
public async Task<MqttPendingApplicationMessage> TakeAsync(CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
// TODO: Create a blocking queue from this.
|
|
||||||
|
|
||||||
while (!cancellationToken.IsCancellationRequested)
|
|
||||||
{
|
{
|
||||||
lock (_messageQueue)
|
return null;
|
||||||
{
|
|
||||||
if (_messageQueue.Count > 0)
|
|
||||||
{
|
|
||||||
return _messageQueue.Dequeue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await _messageQueueLock.WaitOneAsync(cancellationToken).ConfigureAwait(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return dequeueResult.Item;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Enqueue(MqttPendingApplicationMessage enqueuedApplicationMessage)
|
public void Enqueue(MqttQueuedApplicationMessage queuedApplicationMessage)
|
||||||
{
|
{
|
||||||
if (enqueuedApplicationMessage == null) throw new ArgumentNullException(nameof(enqueuedApplicationMessage));
|
if (queuedApplicationMessage == null) throw new ArgumentNullException(nameof(queuedApplicationMessage));
|
||||||
|
|
||||||
lock (_messageQueue)
|
lock (_messageQueue)
|
||||||
{
|
{
|
||||||
@@ -104,14 +63,17 @@ namespace MQTTnet.Server
|
|||||||
|
|
||||||
if (_options.PendingMessagesOverflowStrategy == MqttPendingMessagesOverflowStrategy.DropOldestQueuedMessage)
|
if (_options.PendingMessagesOverflowStrategy == MqttPendingMessagesOverflowStrategy.DropOldestQueuedMessage)
|
||||||
{
|
{
|
||||||
_messageQueue.Dequeue();
|
_messageQueue.TryDequeue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_messageQueue.Enqueue(enqueuedApplicationMessage);
|
_messageQueue.Enqueue(queuedApplicationMessage);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_messageQueueLock.Set();
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_messageQueue.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ namespace MQTTnet.Server
|
|||||||
|
|
||||||
foreach (var connection in _connections.Values)
|
foreach (var connection in _connections.Values)
|
||||||
{
|
{
|
||||||
var clientStatus = new MqttClientStatus(connection, this);
|
var clientStatus = new MqttClientStatus(connection);
|
||||||
connection.FillStatus(clientStatus);
|
connection.FillStatus(clientStatus);
|
||||||
|
|
||||||
var sessionStatus = new MqttSessionStatus(connection.Session, this);
|
var sessionStatus = new MqttSessionStatus(connection.Session, this);
|
||||||
@@ -175,7 +175,8 @@ namespace MQTTnet.Server
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var queuedApplicationMessage = await _messageQueue.DequeueAsync(cancellationToken).ConfigureAwait(false);
|
var dequeueResult = await _messageQueue.TryDequeueAsync(cancellationToken).ConfigureAwait(false);
|
||||||
|
var queuedApplicationMessage = dequeueResult.Item;
|
||||||
|
|
||||||
var sender = queuedApplicationMessage.Sender;
|
var sender = queuedApplicationMessage.Sender;
|
||||||
var applicationMessage = queuedApplicationMessage.ApplicationMessage;
|
var applicationMessage = queuedApplicationMessage.ApplicationMessage;
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
using MQTTnet.Protocol;
|
||||||
|
|
||||||
|
namespace MQTTnet.Server
|
||||||
|
{
|
||||||
|
public class MqttQueuedApplicationMessage
|
||||||
|
{
|
||||||
|
public MqttApplicationMessage ApplicationMessage { get; set; }
|
||||||
|
|
||||||
|
public string SenderClientId { get; set; }
|
||||||
|
|
||||||
|
public bool IsRetainedMessage { get; set; }
|
||||||
|
|
||||||
|
public MqttQualityOfServiceLevel QualityOfServiceLevel { get; set; }
|
||||||
|
|
||||||
|
public bool IsDuplicate { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -26,6 +26,10 @@ namespace MQTTnet.Server.Status
|
|||||||
|
|
||||||
IMqttSessionStatus Session { get; }
|
IMqttSessionStatus Session { get; }
|
||||||
|
|
||||||
|
long BytesSent { get; }
|
||||||
|
|
||||||
|
long BytesReceived { get; }
|
||||||
|
|
||||||
Task DisconnectAsync();
|
Task DisconnectAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,13 +6,11 @@ namespace MQTTnet.Server.Status
|
|||||||
{
|
{
|
||||||
public class MqttClientStatus : IMqttClientStatus
|
public class MqttClientStatus : IMqttClientStatus
|
||||||
{
|
{
|
||||||
private readonly MqttClientSessionsManager _sessionsManager;
|
|
||||||
private readonly MqttClientConnection _connection;
|
private readonly MqttClientConnection _connection;
|
||||||
|
|
||||||
public MqttClientStatus(MqttClientConnection connection, MqttClientSessionsManager sessionsManager)
|
public MqttClientStatus(MqttClientConnection connection)
|
||||||
{
|
{
|
||||||
_connection = connection;
|
_connection = connection;
|
||||||
_sessionsManager = sessionsManager;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public string ClientId { get; set; }
|
public string ClientId { get; set; }
|
||||||
@@ -35,6 +33,10 @@ namespace MQTTnet.Server.Status
|
|||||||
|
|
||||||
public IMqttSessionStatus Session { get; set; }
|
public IMqttSessionStatus Session { get; set; }
|
||||||
|
|
||||||
|
public long BytesSent { get; set; }
|
||||||
|
|
||||||
|
public long BytesReceived { get; set; }
|
||||||
|
|
||||||
public Task DisconnectAsync()
|
public Task DisconnectAsync()
|
||||||
{
|
{
|
||||||
return _connection.StopAsync();
|
return _connection.StopAsync();
|
||||||
|
|||||||
Reference in New Issue
Block a user