Make internal message of server async.

This commit is contained in:
Christian Kratky
2019-04-02 21:51:26 +02:00
parent 35ee732045
commit 2267770a72
15 changed files with 192 additions and 154 deletions
@@ -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);
+33 -18
View File
@@ -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)
+24 -46
View File
@@ -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
+24 -4
View File
@@ -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; }
}
}
+23 -15
View File
@@ -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();