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 static CheckSubscriptionsResult NotSubscribed = new CheckSubscriptionsResult();
public bool IsSubscribed { 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
{
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;
ApplicationMessage = applicationMessage;
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 MqttApplicationMessage ApplicationMessage { get; set; }
@@ -322,19 +322,21 @@ namespace MQTTnet.Server
}
var deliveryCount = 0;
List<MqttClientSession> 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);
if (isSubscribed)
{
deliveryCount++;
}
deliveryCount++;
}
}
if (deliveryCount == 0)
{
var undeliveredMessageInterceptor = _options.UndeliveredMessageInterceptor;
@@ -445,7 +447,13 @@ namespace MQTTnet.Server
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);
return interceptorContext;
}
@@ -193,10 +193,7 @@ namespace MQTTnet.Server
if (qosLevels.Count == 0)
{
return new CheckSubscriptionsResult
{
IsSubscribed = false
};
return CheckSubscriptionsResult.NotSubscribed;
}
return CreateSubscriptionResult(qosLevel, qosLevels);
@@ -3,9 +3,9 @@ using System.Threading.Tasks;
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)
{
@@ -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.Security.Authentication;
using MQTTnet.Certificates;
using System.Threading.Tasks;
#if !WINDOWS_UWP
using System.Security.Cryptography.X509Certificates;
#endif
// ReSharper disable UnusedMember.Global
namespace MQTTnet.Server
{
public class MqttServerOptionsBuilder
@@ -187,6 +189,24 @@ namespace MQTTnet.Server
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)
{
_options.ClientMessageQueueInterceptor = value;
@@ -217,6 +237,12 @@ namespace MQTTnet.Server
return this;
}
public MqttServerOptionsBuilder WithUndeliveredMessageInterceptor(Action<MqttApplicationMessageInterceptorContext> value)
{
_options.UndeliveredMessageInterceptor = new MqttServerApplicationMessageInterceptorDelegate(value);
return this;
}
public MqttServerOptionsBuilder WithDefaultEndpointReuseAddress()
{
_options.DefaultEndpointOptions.ReuseAddress = true;
@@ -248,11 +274,5 @@ namespace MQTTnet.Server
{
return _options;
}
public MqttServerOptionsBuilder WithUndeliveredMessageInterceptor(Action<MqttApplicationMessageInterceptorContext> value)
{
_options.UndeliveredMessageInterceptor = new MqttServerApplicationMessageInterceptorDelegate(value);
return this;
}
}
}