11// Copyright (c) Microsoft Corporation.
22// Licensed under the MIT License.
33
4- using Azure . Iot . Operations . Protocol . Connection ;
54using Azure . Iot . Operations . Protocol . Events ;
65using Azure . Iot . Operations . Protocol . Models ;
76using System ;
@@ -17,78 +16,32 @@ namespace Azure.Iot.Operations.Protocol.Chunking;
1716/// <summary>
1817/// MQTT client middleware that provides transparent chunking of large messages.
1918/// </summary>
20- public class ChunkingMqttClient : IMqttClient
19+ public class ChunkingMqttPubSubClient : IMqttPubSubClient
2120{
22- private readonly IMqttClient _innerClient ;
21+ private readonly IExtendedPubSubMqttClient _innerClient ;
2322 private readonly ChunkingOptions _chunkingOptions ;
2423 private readonly ConcurrentDictionary < string , ChunkedMessageAssembler > _messageAssemblers = new ( ) ;
2524 private readonly ChunkedMessageSplitter _messageSplitter ;
2625 private int _maxPacketSize ;
2726
2827 /// <summary>
29- /// Initializes a new instance of the <see cref="ChunkingMqttClient "/> class.
28+ /// Initializes a new instance of the <see cref="ChunkingMqttPubSubClient "/> class.
3029 /// </summary>
3130 /// <param name="innerClient">The MQTT client to wrap with chunking capabilities.</param>
3231 /// <param name="options">The chunking options.</param>
33- public ChunkingMqttClient ( IMqttClient innerClient , ChunkingOptions ? options = null )
32+ public ChunkingMqttPubSubClient ( IExtendedPubSubMqttClient innerClient , ChunkingOptions ? options = null )
3433 {
3534 _innerClient = innerClient ?? throw new ArgumentNullException ( nameof ( innerClient ) ) ;
3635 _chunkingOptions = options ?? new ChunkingOptions ( ) ;
3736 _messageSplitter = new ChunkedMessageSplitter ( _chunkingOptions ) ;
3837
39- // Hook into the inner client's event
38+ UpdateMaxPacketSizeFromConnectResult ( _innerClient . GetConnectResult ( ) ) ;
39+
4040 _innerClient . ApplicationMessageReceivedAsync += HandleApplicationMessageReceivedAsync ;
41- _innerClient . ConnectedAsync += HandleConnectedAsync ;
42- _innerClient . DisconnectedAsync += HandleDisconnectedAsync ;
4341 }
4442
45- /// <inheritdoc/>
4643 public event Func < MqttApplicationMessageReceivedEventArgs , Task > ? ApplicationMessageReceivedAsync ;
4744
48- /// <inheritdoc/>
49- public event Func < MqttClientDisconnectedEventArgs , Task > ? DisconnectedAsync ;
50-
51- /// <inheritdoc/>
52- public event Func < MqttClientConnectedEventArgs , Task > ? ConnectedAsync ;
53-
54- /// <inheritdoc/>
55- public async Task < MqttClientConnectResult > ConnectAsync ( MqttClientOptions options , CancellationToken cancellationToken = default )
56- {
57- var result = await _innerClient . ConnectAsync ( options , cancellationToken ) ;
58-
59- UpdateMaxPacketSizeFromConnectResult ( result ) ;
60-
61- return result ;
62- }
63-
64- /// <inheritdoc/>
65- public async Task < MqttClientConnectResult > ConnectAsync ( MqttConnectionSettings settings , CancellationToken cancellationToken = default )
66- {
67- var result = await _innerClient . ConnectAsync ( settings , cancellationToken ) ;
68-
69- UpdateMaxPacketSizeFromConnectResult ( result ) ;
70-
71- return result ;
72- }
73-
74- /// <inheritdoc/>
75- public Task DisconnectAsync ( MqttClientDisconnectOptions ? options = null , CancellationToken cancellationToken = default )
76- {
77- return _innerClient . DisconnectAsync ( options , cancellationToken ) ;
78- }
79-
80- public Task ReconnectAsync ( CancellationToken cancellationToken = default )
81- {
82- return _innerClient . ReconnectAsync ( cancellationToken ) ;
83- }
84-
85- public bool IsConnected => _innerClient . IsConnected ;
86-
87- public Task SendEnhancedAuthenticationExchangeDataAsync ( MqttEnhancedAuthenticationExchangeData data , CancellationToken cancellationToken = default )
88- {
89- return _innerClient . SendEnhancedAuthenticationExchangeDataAsync ( data , cancellationToken ) ;
90- }
91-
9245 /// <inheritdoc/>
9346 public async Task < MqttClientPublishResult > PublishAsync ( MqttApplicationMessage applicationMessage , CancellationToken cancellationToken = default )
9447 {
@@ -130,25 +83,21 @@ public ValueTask DisposeAsync()
13083
13184 // Detach events
13285 _innerClient . ApplicationMessageReceivedAsync -= HandleApplicationMessageReceivedAsync ;
133- _innerClient . ConnectedAsync -= HandleConnectedAsync ;
134- _innerClient . DisconnectedAsync -= HandleDisconnectedAsync ;
13586
13687 // Suppress finalization since we're explicitly disposing
13788 GC . SuppressFinalize ( this ) ;
13889
13990 return _innerClient . DisposeAsync ( ) ;
14091 }
14192
142- private void UpdateMaxPacketSizeFromConnectResult ( MqttClientConnectResult result )
93+ private void UpdateMaxPacketSizeFromConnectResult ( MqttClientConnectResult ? result )
14394 {
144- if ( _chunkingOptions . Enabled && result . MaximumPacketSize is not > 0 )
95+ if ( _chunkingOptions . Enabled && result ? . MaximumPacketSize is not > 0 )
14596 {
14697 throw new InvalidOperationException ( "Chunking client requires a defined maximum packet size to function properly." ) ;
14798 }
14899
149- // TODO: @maximsemnov80 figure out how to set the max packet size on the broker side
150- // Interlocked.Exchange(ref _maxPacketSize, (int)result.MaximumPacketSize!.Value);
151- _maxPacketSize = 64 * 1024 ; // 64KB
100+ Interlocked . Exchange ( ref _maxPacketSize , ( int ) result ! . MaximumPacketSize ! . Value ) ;
152101 }
153102
154103 private async Task < MqttClientPublishResult > PublishChunkedMessageAsync ( MqttApplicationMessage message , CancellationToken cancellationToken )
@@ -262,21 +211,4 @@ private static bool TryGetChunkMetadata(MqttApplicationMessage message, out Chun
262211 return false ;
263212 }
264213 }
265-
266- private Task HandleConnectedAsync ( MqttClientConnectedEventArgs args )
267- {
268- // Forward the event
269- var handler = ConnectedAsync ;
270- return handler != null ? handler . Invoke ( args ) : Task . CompletedTask ;
271- }
272-
273- private Task HandleDisconnectedAsync ( MqttClientDisconnectedEventArgs args )
274- {
275- // Clear any in-progress reassembly when disconnected
276- _messageAssemblers . Clear ( ) ;
277-
278- // Forward the event
279- var handler = DisconnectedAsync ;
280- return handler != null ? handler . Invoke ( args ) : Task . CompletedTask ;
281- }
282214}
0 commit comments