mirror of
https://github.com/dotnet/MQTTnet.git
synced 2026-10-18 10:26:11 +08:00
Refactor ConnectedClient statistics API
This commit is contained in:
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user