Add new multi threaded application message handler for server.

This commit is contained in:
Christian
2020-12-13 11:36:31 +01:00
parent 86256d1b10
commit f92cfcd293
7 changed files with 105 additions and 25 deletions
@@ -4,6 +4,8 @@ namespace MQTTnet.Server
{ {
public struct CheckSubscriptionsResult public struct CheckSubscriptionsResult
{ {
public static CheckSubscriptionsResult NotSubscribed = new CheckSubscriptionsResult();
public bool IsSubscribed { get; set; } public bool IsSubscribed { get; set; }
public MqttQualityOfServiceLevel QualityOfServiceLevel { get; set; } public MqttQualityOfServiceLevel QualityOfServiceLevel { get; set; }
@@ -1,16 +1,23 @@
using System.Collections.Generic; using System;
using System.Collections.Generic;
using MQTTnet.Diagnostics;
namespace MQTTnet.Server namespace MQTTnet.Server
{ {
public class MqttApplicationMessageInterceptorContext public sealed class MqttApplicationMessageInterceptorContext
{ {
public MqttApplicationMessageInterceptorContext(string clientId, IDictionary<object, object> sessionItems, MqttApplicationMessage applicationMessage) public MqttApplicationMessageInterceptorContext(string clientId, IDictionary<object, object> sessionItems, IMqttNetScopedLogger logger)
{ {
ClientId = clientId; ClientId = clientId;
ApplicationMessage = applicationMessage;
SessionItems = sessionItems; SessionItems = sessionItems;
Logger = logger ?? throw new ArgumentNullException(nameof(logger));
} }
/// <summary>
/// Gets the currently used logger.
/// </summary>
public IMqttNetScopedLogger Logger { get; }
public string ClientId { get; } public string ClientId { get; }
public MqttApplicationMessage ApplicationMessage { get; set; } public MqttApplicationMessage ApplicationMessage { get; set; }
@@ -322,19 +322,21 @@ namespace MQTTnet.Server
} }
var deliveryCount = 0; var deliveryCount = 0;
List<MqttClientSession> sessions;
lock (_sessions) lock (_sessions)
{ {
foreach (var clientSession in _sessions.Values) sessions = _sessions.Values.ToList();
}
foreach (var clientSession in sessions)
{
var isSubscribed = clientSession.EnqueueApplicationMessage(applicationMessage, senderClientId, false);
if (isSubscribed)
{ {
var isSubscribed = clientSession.EnqueueApplicationMessage(applicationMessage, senderClientId, false); deliveryCount++;
if (isSubscribed)
{
deliveryCount++;
}
} }
} }
if (deliveryCount == 0) if (deliveryCount == 0)
{ {
var undeliveredMessageInterceptor = _options.UndeliveredMessageInterceptor; var undeliveredMessageInterceptor = _options.UndeliveredMessageInterceptor;
@@ -445,7 +447,13 @@ namespace MQTTnet.Server
sessionItems = clientConnection.Session.Items; sessionItems = clientConnection.Session.Items;
} }
var interceptorContext = new MqttApplicationMessageInterceptorContext(senderClientId, sessionItems, applicationMessage); var interceptorContext = new MqttApplicationMessageInterceptorContext(senderClientId, sessionItems, _logger)
{
AcceptPublish = true,
ApplicationMessage = applicationMessage,
CloseConnection = false
};
await interceptor.InterceptApplicationMessagePublishAsync(interceptorContext).ConfigureAwait(false); await interceptor.InterceptApplicationMessagePublishAsync(interceptorContext).ConfigureAwait(false);
return interceptorContext; return interceptorContext;
} }
@@ -193,10 +193,7 @@ namespace MQTTnet.Server
if (qosLevels.Count == 0) if (qosLevels.Count == 0)
{ {
return new CheckSubscriptionsResult return CheckSubscriptionsResult.NotSubscribed;
{
IsSubscribed = false
};
} }
return CreateSubscriptionResult(qosLevel, qosLevels); return CreateSubscriptionResult(qosLevel, qosLevels);
@@ -3,9 +3,9 @@ using System.Threading.Tasks;
namespace MQTTnet.Server namespace MQTTnet.Server
{ {
public class MqttServerApplicationMessageInterceptorDelegate : IMqttServerApplicationMessageInterceptor public sealed class MqttServerApplicationMessageInterceptorDelegate : IMqttServerApplicationMessageInterceptor
{ {
private readonly Func<MqttApplicationMessageInterceptorContext, Task> _callback; readonly Func<MqttApplicationMessageInterceptorContext, Task> _callback;
public MqttServerApplicationMessageInterceptorDelegate(Action<MqttApplicationMessageInterceptorContext> callback) public MqttServerApplicationMessageInterceptorDelegate(Action<MqttApplicationMessageInterceptorContext> callback)
{ {
@@ -0,0 +1,46 @@
using System;
using System.Threading.Tasks;
using MQTTnet.Diagnostics;
using MQTTnet.Implementations;
using MQTTnet.Internal;
namespace MQTTnet.Server
{
public sealed class MqttServerMultiThreadedApplicationMessageInterceptorDelegate : IMqttServerApplicationMessageInterceptor
{
readonly Func<MqttApplicationMessageInterceptorContext, Task> _callback;
public MqttServerMultiThreadedApplicationMessageInterceptorDelegate(Action<MqttApplicationMessageInterceptorContext> callback)
{
if (callback == null) throw new ArgumentNullException(nameof(callback));
_callback = context =>
{
callback(context);
return Task.FromResult(0);
};
}
public MqttServerMultiThreadedApplicationMessageInterceptorDelegate(Func<MqttApplicationMessageInterceptorContext, Task> callback)
{
_callback = callback ?? throw new ArgumentNullException(nameof(callback));
}
public Task InterceptApplicationMessagePublishAsync(MqttApplicationMessageInterceptorContext context)
{
Task.Run(async () =>
{
try
{
await _callback.Invoke(context).ConfigureAwait(false);
}
catch (Exception exception)
{
context.Logger.Error(exception, "Error while intercepting application message.");
}
}).RunInBackground();
return PlatformAbstractionLayer.CompletedTask;
}
}
}
@@ -3,11 +3,13 @@ using System.Net;
using System.Net.Security; using System.Net.Security;
using System.Security.Authentication; using System.Security.Authentication;
using MQTTnet.Certificates; using MQTTnet.Certificates;
using System.Threading.Tasks;
#if !WINDOWS_UWP #if !WINDOWS_UWP
using System.Security.Cryptography.X509Certificates; using System.Security.Cryptography.X509Certificates;
#endif #endif
// ReSharper disable UnusedMember.Global
namespace MQTTnet.Server namespace MQTTnet.Server
{ {
public class MqttServerOptionsBuilder public class MqttServerOptionsBuilder
@@ -187,6 +189,24 @@ namespace MQTTnet.Server
return this; return this;
} }
public MqttServerOptionsBuilder WithApplicationMessageInterceptor(Func<MqttApplicationMessageInterceptorContext, Task> value)
{
_options.ApplicationMessageInterceptor = new MqttServerApplicationMessageInterceptorDelegate(value);
return this;
}
public MqttServerOptionsBuilder WithMultiThreadedApplicationMessageInterceptor(Action<MqttApplicationMessageInterceptorContext> value)
{
_options.ApplicationMessageInterceptor = new MqttServerMultiThreadedApplicationMessageInterceptorDelegate(value);
return this;
}
public MqttServerOptionsBuilder WithMultiThreadedApplicationMessageInterceptor(Func<MqttApplicationMessageInterceptorContext, Task> value)
{
_options.ApplicationMessageInterceptor = new MqttServerMultiThreadedApplicationMessageInterceptorDelegate(value);
return this;
}
public MqttServerOptionsBuilder WithClientMessageQueueInterceptor(IMqttServerClientMessageQueueInterceptor value) public MqttServerOptionsBuilder WithClientMessageQueueInterceptor(IMqttServerClientMessageQueueInterceptor value)
{ {
_options.ClientMessageQueueInterceptor = value; _options.ClientMessageQueueInterceptor = value;
@@ -217,6 +237,12 @@ namespace MQTTnet.Server
return this; return this;
} }
public MqttServerOptionsBuilder WithUndeliveredMessageInterceptor(Action<MqttApplicationMessageInterceptorContext> value)
{
_options.UndeliveredMessageInterceptor = new MqttServerApplicationMessageInterceptorDelegate(value);
return this;
}
public MqttServerOptionsBuilder WithDefaultEndpointReuseAddress() public MqttServerOptionsBuilder WithDefaultEndpointReuseAddress()
{ {
_options.DefaultEndpointOptions.ReuseAddress = true; _options.DefaultEndpointOptions.ReuseAddress = true;
@@ -248,11 +274,5 @@ namespace MQTTnet.Server
{ {
return _options; return _options;
} }
public MqttServerOptionsBuilder WithUndeliveredMessageInterceptor(Action<MqttApplicationMessageInterceptorContext> value)
{
_options.UndeliveredMessageInterceptor = new MqttServerApplicationMessageInterceptorDelegate(value);
return this;
}
} }
} }