Refactor ConnectedClient statistics API

This commit is contained in:
Christian
2018-05-16 00:08:42 +02:00
parent 719838de3b
commit fbf1cbc76e
24 changed files with 306 additions and 350 deletions
@@ -1,6 +1,6 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using MQTTnet.Adapter;
@@ -14,8 +14,8 @@ namespace MQTTnet.Server
{
public sealed class MqttClientSessionsManager : IDisposable
{
private readonly Dictionary<string, MqttClientSession> _sessions = new Dictionary<string, MqttClientSession>();
private readonly AsyncLock _sessionsLock = new AsyncLock();
private readonly ConcurrentDictionary<string, MqttClientSession> _sessions = new ConcurrentDictionary<string, MqttClientSession>();
private readonly AsyncLock _sessionPreparationLock = new AsyncLock();
private readonly MqttRetainedMessagesManager _retainedMessagesManager;
private readonly IMqttServerOptions _options;
@@ -38,7 +38,6 @@ namespace MQTTnet.Server
{
var clientId = string.Empty;
var wasCleanDisconnect = false;
MqttClientSession clientSession = null;
try
{
@@ -69,7 +68,7 @@ namespace MQTTnet.Server
}
var result = await PrepareClientSessionAsync(connectPacket).ConfigureAwait(false);
clientSession = result.Session;
var clientSession = result.Session;
await clientAdapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, new[]
{
@@ -80,11 +79,7 @@ namespace MQTTnet.Server
}
}, cancellationToken).ConfigureAwait(false);
Server.OnClientConnected(new ConnectedMqttClient
{
ClientId = clientId,
ProtocolVersion = clientAdapter.PacketSerializer.ProtocolVersion
});
Server.OnClientConnected(clientId);
wasCleanDisconnect = await clientSession.RunAsync(connectPacket, clientAdapter).ConfigureAwait(false);
}
@@ -109,55 +104,36 @@ namespace MQTTnet.Server
if (!_options.EnablePersistentSessions)
{
await DeleteSessionAsync(clientId).ConfigureAwait(false);
DeleteSession(clientId);
}
Server.OnClientDisconnected(new ConnectedMqttClient
{
ClientId = clientId,
ProtocolVersion = clientAdapter.PacketSerializer.ProtocolVersion,
PendingApplicationMessages = clientSession?.PendingMessagesQueue.Count ?? 0
},
wasCleanDisconnect);
Server.OnClientDisconnected(clientId, wasCleanDisconnect);
}
}
public async Task StopAsync()
public Task StopAsync()
{
await _sessionsLock.EnterAsync(CancellationToken.None).ConfigureAwait(false);
try
foreach (var session in _sessions)
{
foreach (var session in _sessions)
{
session.Value.Stop(MqttClientDisconnectType.NotClean);
}
session.Value.Stop(MqttClientDisconnectType.NotClean);
}
_sessions.Clear();
}
finally
{
_sessionsLock.Exit();
}
_sessions.Clear();
return Task.FromResult(0);
}
public async Task<IList<ConnectedMqttClient>> GetConnectedClientsAsync()
public Task<IList<IMqttClientSessionStatus>> GetClientStatusAsync()
{
await _sessionsLock.EnterAsync(CancellationToken.None).ConfigureAwait(false);
try
var result = new List<IMqttClientSessionStatus>();
foreach (var session in _sessions)
{
return _sessions.Where(s => s.Value.IsConnected).Select(s => new ConnectedMqttClient
{
ClientId = s.Value.ClientId,
ProtocolVersion = s.Value.ProtocolVersion,
LastPacketReceived = s.Value.KeepAliveMonitor.LastPacketReceived,
LastNonKeepAlivePacketReceived = s.Value.KeepAliveMonitor.LastNonKeepAlivePacketReceived,
PendingApplicationMessages = s.Value.PendingMessagesQueue.Count
}).ToList();
}
finally
{
_sessionsLock.Exit();
var status = new MqttClientSessionStatus(this, session.Value);
session.Value.FillStatus(status);
result.Add(status);
}
return Task.FromResult((IList<IMqttClientSessionStatus>)result);
}
public void StartDispatchApplicationMessage(MqttClientSession senderClientSession, MqttApplicationMessage applicationMessage)
@@ -165,51 +141,41 @@ namespace MQTTnet.Server
Task.Run(() => DispatchApplicationMessageAsync(senderClientSession, applicationMessage));
}
public async Task SubscribeAsync(string clientId, IList<TopicFilter> topicFilters)
public Task SubscribeAsync(string clientId, IList<TopicFilter> topicFilters)
{
if (clientId == null) throw new ArgumentNullException(nameof(clientId));
if (topicFilters == null) throw new ArgumentNullException(nameof(topicFilters));
await _sessionsLock.EnterAsync(CancellationToken.None).ConfigureAwait(false);
try
if (!_sessions.TryGetValue(clientId, out var session))
{
if (!_sessions.TryGetValue(clientId, out var session))
{
throw new InvalidOperationException($"Client session '{clientId}' is unknown.");
}
throw new InvalidOperationException($"Client session '{clientId}' is unknown.");
}
await session.SubscribeAsync(topicFilters).ConfigureAwait(false);
}
finally
{
_sessionsLock.Exit();
}
return session.SubscribeAsync(topicFilters);
}
public async Task UnsubscribeAsync(string clientId, IList<string> topicFilters)
public Task UnsubscribeAsync(string clientId, IList<string> topicFilters)
{
if (clientId == null) throw new ArgumentNullException(nameof(clientId));
if (topicFilters == null) throw new ArgumentNullException(nameof(topicFilters));
await _sessionsLock.EnterAsync(CancellationToken.None).ConfigureAwait(false);
try
if (!_sessions.TryGetValue(clientId, out var session))
{
if (!_sessions.TryGetValue(clientId, out var session))
{
throw new InvalidOperationException($"Client session '{clientId}' is unknown.");
}
throw new InvalidOperationException($"Client session '{clientId}' is unknown.");
}
await session.UnsubscribeAsync(topicFilters).ConfigureAwait(false);
}
finally
{
_sessionsLock.Exit();
}
return session.UnsubscribeAsync(topicFilters);
}
public void DeleteSession(string clientId)
{
_sessions.TryRemove(clientId, out _);
_logger.Verbose("Session for client '{0}' deleted.", clientId);
}
public void Dispose()
{
_sessionsLock?.Dispose();
_sessionPreparationLock?.Dispose();
}
private MqttConnectReturnCode ValidateConnection(MqttConnectPacket connectPacket)
@@ -229,23 +195,9 @@ namespace MQTTnet.Server
return context.ReturnCode;
}
private async Task DeleteSessionAsync(string clientId)
{
await _sessionsLock.EnterAsync(CancellationToken.None);
try
{
_sessions.Remove(clientId);
_logger.Verbose("Session for client '{0}' deleted.", clientId);
}
finally
{
_sessionsLock.Exit();
}
}
private async Task<GetOrCreateClientSessionResult> PrepareClientSessionAsync(MqttConnectPacket connectPacket)
{
await _sessionsLock.EnterAsync(CancellationToken.None).ConfigureAwait(false);
await _sessionPreparationLock.EnterAsync(CancellationToken.None).ConfigureAwait(false);
try
{
var isSessionPresent = _sessions.TryGetValue(connectPacket.ClientId, out var clientSession);
@@ -253,7 +205,7 @@ namespace MQTTnet.Server
{
if (connectPacket.CleanSession)
{
_sessions.Remove(connectPacket.ClientId);
_sessions.TryRemove(connectPacket.ClientId, out _);
clientSession.Stop(MqttClientDisconnectType.Clean);
clientSession.Dispose();
@@ -282,7 +234,7 @@ namespace MQTTnet.Server
}
finally
{
_sessionsLock.Exit();
_sessionPreparationLock.Exit();
}
}
@@ -301,30 +253,22 @@ namespace MQTTnet.Server
return;
}
Server.OnApplicationMessageReceived(senderClientSession?.ClientId, applicationMessage);
if (applicationMessage.Retain)
{
await _retainedMessagesManager.HandleMessageAsync(senderClientSession?.ClientId, applicationMessage).ConfigureAwait(false);
}
Server.OnApplicationMessageReceived(senderClientSession?.ClientId, applicationMessage);
foreach (var clientSession in _sessions.Values)
{
clientSession.EnqueueApplicationMessage(applicationMessage);
}
}
catch (Exception exception)
{
_logger.Error(exception, "Error while processing application message");
}
await _sessionsLock.EnterAsync(CancellationToken.None).ConfigureAwait(false);
try
{
foreach (var clientSession in _sessions.Values)
{
await clientSession.EnqueueApplicationMessageAsync(applicationMessage).ConfigureAwait(false);
}
}
finally
{
_sessionsLock.Exit();
}
}
private MqttApplicationMessageInterceptorContext InterceptApplicationMessage(MqttClientSession senderClientSession, MqttApplicationMessage applicationMessage)