@@ -145,6 +145,12 @@ namespace MQTTnet.AspNetCore | |||
return null; | |||
} | |||
public void ResetStatistics() | |||
{ | |||
BytesReceived = 0; | |||
BytesSent = 0; | |||
} | |||
public async Task SendPacketAsync(MqttBasePacket packet, TimeSpan timeout, CancellationToken cancellationToken) | |||
{ | |||
var formatter = PacketFormatterAdapter; | |||
@@ -32,5 +32,7 @@ namespace MQTTnet.Adapter | |||
Task SendPacketAsync(MqttBasePacket packet, TimeSpan timeout, CancellationToken cancellationToken); | |||
Task<MqttBasePacket> ReceivePacketAsync(TimeSpan timeout, CancellationToken cancellationToken); | |||
void ResetStatistics(); | |||
} | |||
} |
@@ -14,7 +14,7 @@ using MQTTnet.Server.Status; | |||
namespace MQTTnet.Server | |||
{ | |||
public class MqttClientConnection : IMqttClientSession, IDisposable | |||
public class MqttClientConnection : IDisposable | |||
{ | |||
private readonly MqttPacketIdentifierProvider _packetIdentifierProvider = new MqttPacketIdentifierProvider(); | |||
private readonly MqttPacketDispatcher _packetDispatcher = new MqttPacketDispatcher(); | |||
@@ -64,7 +64,7 @@ namespace MQTTnet.Server | |||
if (logger == null) throw new ArgumentNullException(nameof(logger)); | |||
_logger = logger.CreateChildLogger(nameof(MqttClientConnection)); | |||
_keepAliveMonitor = new MqttClientKeepAliveMonitor(this, _logger); | |||
_keepAliveMonitor = new MqttClientKeepAliveMonitor(_connectPacket.ClientId, StopAsync, _logger); | |||
_connectedTimestamp = DateTime.UtcNow; | |||
_lastPacketReceivedTimestamp = _connectedTimestamp; | |||
@@ -86,6 +86,11 @@ namespace MQTTnet.Server | |||
} | |||
} | |||
public void ResetStatistics() | |||
{ | |||
_channelAdapter.ResetStatistics(); | |||
} | |||
public void FillStatus(MqttClientStatus status) | |||
{ | |||
status.ClientId = ClientId; | |||
@@ -10,17 +10,18 @@ namespace MQTTnet.Server | |||
{ | |||
private readonly Stopwatch _lastPacketReceivedTracker = new Stopwatch(); | |||
private readonly IMqttClientSession _clientSession; | |||
private readonly string _clientId; | |||
private readonly Func<Task> _keepAliveElapsedCallback; | |||
private readonly IMqttNetChildLogger _logger; | |||
private bool _isPaused; | |||
public MqttClientKeepAliveMonitor(IMqttClientSession clientSession, IMqttNetChildLogger logger) | |||
public MqttClientKeepAliveMonitor(string clientId, Func<Task> keepAliveElapsedCallback, IMqttNetChildLogger logger) | |||
{ | |||
_clientId = clientId ?? throw new ArgumentNullException(nameof(clientId)); | |||
_keepAliveElapsedCallback = keepAliveElapsedCallback ?? throw new ArgumentNullException(nameof(keepAliveElapsedCallback)); | |||
if (logger == null) throw new ArgumentNullException(nameof(logger)); | |||
_clientSession = clientSession ?? throw new ArgumentNullException(nameof(clientSession)); | |||
_logger = logger.CreateChildLogger(nameof(MqttClientKeepAliveMonitor)); | |||
} | |||
@@ -62,8 +63,8 @@ namespace MQTTnet.Server | |||
// If the client sends 1 sec. the server will allow up to 1.5 seconds. | |||
if (!_isPaused && _lastPacketReceivedTracker.Elapsed.TotalSeconds >= keepAlivePeriod * 1.5D) | |||
{ | |||
_logger.Warning(null, "Client '{0}': Did not receive any packet or keep alive signal.", _clientSession.ClientId); | |||
await _clientSession.StopAsync().ConfigureAwait(false); | |||
_logger.Warning(null, "Client '{0}': Did not receive any packet or keep alive signal.", _clientId); | |||
await _keepAliveElapsedCallback().ConfigureAwait(false); | |||
return; | |||
} | |||
@@ -80,11 +81,11 @@ namespace MQTTnet.Server | |||
} | |||
catch (Exception exception) | |||
{ | |||
_logger.Error(exception, "Client '{0}': Unhandled exception while checking keep alive timeouts.", _clientSession.ClientId); | |||
_logger.Error(exception, "Client '{0}': Unhandled exception while checking keep alive timeouts.", _clientId); | |||
} | |||
finally | |||
{ | |||
_logger.Verbose("Client '{0}': Stopped checking keep alive timeout.", _clientSession.ClientId); | |||
_logger.Verbose("Client '{0}': Stopped checking keep alive timeout.", _clientId); | |||
} | |||
} | |||
} | |||
@@ -29,7 +29,9 @@ namespace MQTTnet.Server.Status | |||
long BytesSent { get; } | |||
long BytesReceived { get; } | |||
Task DisconnectAsync(); | |||
void ResetStatistics(); | |||
} | |||
} |
@@ -43,5 +43,10 @@ namespace MQTTnet.Server.Status | |||
{ | |||
return _connection.StopAsync(); | |||
} | |||
public void ResetStatistics() | |||
{ | |||
_connection.ResetStatistics(); | |||
} | |||
} | |||
} |
@@ -69,6 +69,10 @@ namespace MQTTnet.Tests.Mockups | |||
}, cancellationToken); | |||
} | |||
public void ResetStatistics() | |||
{ | |||
} | |||
private void EnqueuePacketInternal(MqttBasePacket packet) | |||
{ | |||
if (packet == null) throw new ArgumentNullException(nameof(packet)); | |||
@@ -16,31 +16,43 @@ namespace MQTTnet.Tests | |||
[TestMethod] | |||
public void KeepAlive_Timeout() | |||
{ | |||
var clientSession = new TestClientSession(); | |||
var monitor = new MqttClientKeepAliveMonitor(clientSession, new MqttNetLogger().CreateChildLogger()); | |||
var counter = 0; | |||
Assert.AreEqual(0, clientSession.StopCalledCount); | |||
var monitor = new MqttClientKeepAliveMonitor("", () => | |||
{ | |||
counter++; | |||
return Task.CompletedTask; | |||
}, | |||
new MqttNetLogger().CreateChildLogger()); | |||
Assert.AreEqual(0, counter); | |||
monitor.Start(1, CancellationToken.None); | |||
Assert.AreEqual(0, clientSession.StopCalledCount); | |||
Assert.AreEqual(0, counter); | |||
Thread.Sleep(2000); // Internally the keep alive timeout is multiplied with 1.5 as per protocol specification. | |||
Assert.AreEqual(1, clientSession.StopCalledCount); | |||
Assert.AreEqual(1, counter); | |||
} | |||
[TestMethod] | |||
public void KeepAlive_NoTimeout() | |||
{ | |||
var clientSession = new TestClientSession(); | |||
var monitor = new MqttClientKeepAliveMonitor(clientSession, new MqttNetLogger().CreateChildLogger()); | |||
var counter = 0; | |||
var monitor = new MqttClientKeepAliveMonitor("", () => | |||
{ | |||
counter++; | |||
return Task.CompletedTask; | |||
}, | |||
new MqttNetLogger().CreateChildLogger()); | |||
Assert.AreEqual(0, clientSession.StopCalledCount); | |||
Assert.AreEqual(0, counter); | |||
monitor.Start(1, CancellationToken.None); | |||
Assert.AreEqual(0, clientSession.StopCalledCount); | |||
Assert.AreEqual(0, counter); | |||
// Simulate traffic. | |||
Thread.Sleep(1000); // Internally the keep alive timeout is multiplied with 1.5 as per protocol specification. | |||
@@ -49,11 +61,11 @@ namespace MQTTnet.Tests | |||
monitor.PacketReceived(); | |||
Thread.Sleep(1000); | |||
Assert.AreEqual(0, clientSession.StopCalledCount); | |||
Assert.AreEqual(0, counter); | |||
Thread.Sleep(2000); | |||
Assert.AreEqual(1, clientSession.StopCalledCount); | |||
Assert.AreEqual(1, counter); | |||
} | |||
private class TestClientSession : IMqttClientSession | |||