@@ -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); | |||||
if (isSubscribed) | |||||
{ | |||||
deliveryCount++; | |||||
} | |||||
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 | |||||
{ | |||||
IsSubscribed = false | |||||
}; | |||||
return CheckSubscriptionsResult.NotSubscribed; | |||||
} | } | ||||
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; | |||||
} | |||||
} | } | ||||
} | } |