@@ -16,7 +16,8 @@ | |||||
* [AspNetCore] Adjusted some namespaces (BREAKING CHANGE!) | * [AspNetCore] Adjusted some namespaces (BREAKING CHANGE!) | ||||
* [Server] Adjusted some namespaces (BREAKING CHANGE!) | * [Server] Adjusted some namespaces (BREAKING CHANGE!) | ||||
* [Server] Added state checks (throw if not started etc.) for most server APIs. | * [Server] Added state checks (throw if not started etc.) for most server APIs. | ||||
* [Server] Exposed real X509Certificate2 (instead byte array) to TLS options (thanks to @borigas). | |||||
* [Server] Exposed real X509Certificate2 (instead byte array) to TLS options (Thanks to @borigas). | |||||
* [Core] Added server interceptor for undelivered messages (Thanks to @cshark-inator). | |||||
</releaseNotes> | </releaseNotes> | ||||
<copyright>Copyright Christian Kratky 2016-2020</copyright> | <copyright>Copyright Christian Kratky 2016-2020</copyright> | ||||
<tags>MQTT Message Queue Telemetry Transport MQTTClient MQTTServer Server MQTTBroker Broker NETStandard IoT InternetOfThings Messaging Hardware Arduino Sensor Actuator M2M ESP Smart Home Cities Automation Xamarin Blazor</tags> | <tags>MQTT Message Queue Telemetry Transport MQTTClient MQTTServer Server MQTTBroker Broker NETStandard IoT InternetOfThings Messaging Hardware Arduino Sensor Actuator M2M ESP Smart Home Cities Automation Xamarin Blazor</tags> | ||||
@@ -29,5 +29,7 @@ namespace MQTTnet | |||||
public byte[] CorrelationData { get; set; } | public byte[] CorrelationData { get; set; } | ||||
public List<uint> SubscriptionIdentifiers { get; set; } | public List<uint> SubscriptionIdentifiers { get; set; } | ||||
public uint DeliveryCount { get; set; } | |||||
} | } | ||||
} | } |
@@ -25,5 +25,7 @@ namespace MQTTnet.Server | |||||
IMqttServerStorage Storage { get; } | IMqttServerStorage Storage { get; } | ||||
IMqttRetainedMessagesManager RetainedMessagesManager { get; } | IMqttRetainedMessagesManager RetainedMessagesManager { get; } | ||||
IMqttServerApplicationMessageInterceptor UndeliveredMessageInterceptor { get; set; } | |||||
} | } | ||||
} | } |
@@ -56,6 +56,8 @@ namespace MQTTnet.Server | |||||
_logger.Verbose("Queued application message with topic '{0}' (ClientId: {1}).", applicationMessage.Topic, ClientId); | _logger.Verbose("Queued application message with topic '{0}' (ClientId: {1}).", applicationMessage.Topic, ClientId); | ||||
applicationMessage.DeliveryCount++; | |||||
ApplicationMessagesQueue.Enqueue(applicationMessage, senderClientId, checkSubscriptionsResult.QualityOfServiceLevel, isRetainedApplicationMessage); | ApplicationMessagesQueue.Enqueue(applicationMessage, senderClientId, checkSubscriptionsResult.QualityOfServiceLevel, isRetainedApplicationMessage); | ||||
} | } | ||||
@@ -224,6 +224,8 @@ namespace MQTTnet.Server | |||||
await _retainedMessagesManager.HandleMessageAsync(sender?.ClientId, applicationMessage).ConfigureAwait(false); | await _retainedMessagesManager.HandleMessageAsync(sender?.ClientId, applicationMessage).ConfigureAwait(false); | ||||
} | } | ||||
applicationMessage.DeliveryCount = 0; | |||||
foreach (var clientSession in _sessions.Values) | foreach (var clientSession in _sessions.Values) | ||||
{ | { | ||||
clientSession.EnqueueApplicationMessage( | clientSession.EnqueueApplicationMessage( | ||||
@@ -231,6 +233,16 @@ namespace MQTTnet.Server | |||||
sender?.ClientId, | sender?.ClientId, | ||||
false); | false); | ||||
} | } | ||||
if (applicationMessage.DeliveryCount == 0) | |||||
{ | |||||
if (_options.UndeliveredMessageInterceptor == null) | |||||
{ | |||||
throw new OperationCanceledException(nameof(_options.UndeliveredMessageInterceptor)); | |||||
} | |||||
await _options.UndeliveredMessageInterceptor.InterceptApplicationMessagePublishAsync(new MqttApplicationMessageInterceptorContext(sender?.ClientId, sender?.Session?.Items, applicationMessage)); | |||||
} | |||||
} | } | ||||
catch (OperationCanceledException) | catch (OperationCanceledException) | ||||
{ | { | ||||
@@ -31,5 +31,7 @@ namespace MQTTnet.Server | |||||
public IMqttServerStorage Storage { get; set; } | public IMqttServerStorage Storage { get; set; } | ||||
public IMqttRetainedMessagesManager RetainedMessagesManager { get; set; } = new MqttRetainedMessagesManager(); | public IMqttRetainedMessagesManager RetainedMessagesManager { get; set; } = new MqttRetainedMessagesManager(); | ||||
public IMqttServerApplicationMessageInterceptor UndeliveredMessageInterceptor { get; set; } | |||||
} | } | ||||
} | } |
@@ -212,5 +212,11 @@ namespace MQTTnet.Server | |||||
{ | { | ||||
return _options; | return _options; | ||||
} | } | ||||
public MqttServerOptionsBuilder WithUndeliveredMessageInterceptor(Action<MqttApplicationMessageInterceptorContext> value) | |||||
{ | |||||
_options.UndeliveredMessageInterceptor = new MqttServerApplicationMessageInterceptorDelegate(value); | |||||
return this; | |||||
} | |||||
} | } | ||||
} | } |
@@ -1384,5 +1384,33 @@ namespace MQTTnet.Tests | |||||
Assert.AreEqual(expectedReceivedMessagesCount, receivedMessagesCount); | Assert.AreEqual(expectedReceivedMessagesCount, receivedMessagesCount); | ||||
} | } | ||||
} | } | ||||
[TestMethod] | |||||
public async Task Intercept_Undelivered() | |||||
{ | |||||
using (var testEnvironment = new TestEnvironment()) | |||||
{ | |||||
var undeliverd = string.Empty; | |||||
var svr = await testEnvironment.StartServerAsync(new MqttServerOptionsBuilder().WithUndeliveredMessageInterceptor( | |||||
context => | |||||
{ | |||||
undeliverd = context.ApplicationMessage.Topic; | |||||
})); | |||||
var topicAReceived = false; | |||||
var topicBReceived = false; | |||||
var client = await testEnvironment.ConnectClientAsync(); | |||||
await client.SubscribeAsync("b"); | |||||
await client.PublishAsync("a", null, MqttQualityOfServiceLevel.ExactlyOnce); | |||||
await Task.Delay(500); | |||||
Assert.AreEqual(undeliverd, "a"); | |||||
} | |||||
} | |||||
} | } | ||||
} | } |