@@ -32,18 +32,42 @@ public ChunkedMessageSplitter(ChunkingOptions options)
3232 /// <param name="message">The original message to split.</param>
3333 /// <param name="maxPacketSize">The maximum packet size allowed.</param>
3434 /// <returns>A list of chunked messages.</returns>
35- public IReadOnlyList < MqttApplicationMessage > SplitMessage ( MqttApplicationMessage message , int maxPacketSize )
35+ public IReadOnlyList < MqttApplicationMessage > SplitMessage ( MqttApplicationMessage message , int maxPacketSize )
36+ {
37+ var maxChunkSize = ValidateAndGetMaxChunkSize ( message , maxPacketSize ) ;
38+ var ( payload , totalChunks , messageId , checksum , userProperties ) = PrepareChunkingMetadata ( message , maxChunkSize ) ;
39+
40+ // Create chunks
41+ var chunks = new List < MqttApplicationMessage > ( totalChunks ) ;
42+
43+ for ( var chunkIndex = 0 ; chunkIndex < totalChunks ; chunkIndex ++ )
44+ {
45+ var chunkPayload = ChunkedMessageSplitter . ExtractChunkPayload ( payload , chunkIndex , maxChunkSize ) ;
46+ var chunkMessage = CreateChunk ( message , chunkPayload , userProperties , messageId , chunkIndex , totalChunks , checksum ) ;
47+ chunks . Add ( chunkMessage ) ;
48+ }
49+
50+ return chunks ;
51+ }
52+
53+ private int ValidateAndGetMaxChunkSize ( MqttApplicationMessage message , int maxPacketSize )
3654 {
3755 ArgumentNullException . ThrowIfNull ( message ) ;
3856 ArgumentOutOfRangeException . ThrowIfLessThan ( maxPacketSize , 128 ) ; // minimum MQTT 5.0 protocol compliance.
3957
4058 // Calculate the maximum size for each chunk's payload
41- var maxChunkSize = GetMaxChunkSize ( maxPacketSize ) ;
59+ var maxChunkSize = Utils . GetMaxChunkSize ( maxPacketSize , _options . StaticOverhead ) ;
4260 if ( message . Payload . Length <= maxChunkSize )
4361 {
4462 throw new ArgumentException ( $ "Message size { message . Payload . Length } is less than the maximum chunk size { maxChunkSize } .", nameof ( message ) ) ;
4563 }
4664
65+ return maxChunkSize ;
66+ }
67+
68+ private ( ReadOnlySequence < byte > Payload , int TotalChunks , string MessageId , string Checksum , List < MqttUserProperty > UserProperties )
69+ PrepareChunkingMetadata ( MqttApplicationMessage message , int maxChunkSize )
70+ {
4771 var payload = message . Payload ;
4872 var totalChunks = ( int ) Math . Ceiling ( ( double ) payload . Length / maxChunkSize ) ;
4973
@@ -56,56 +80,53 @@ public IReadOnlyList<MqttApplicationMessage> SplitMessage(MqttApplicationMessage
5680 // Create a copy of the user properties
5781 var userProperties = new List < MqttUserProperty > ( message . UserProperties ?? Enumerable . Empty < MqttUserProperty > ( ) ) ;
5882
59- // Create chunks
60- var chunks = new List < MqttApplicationMessage > ( totalChunks ) ;
61-
62- for ( var chunkIndex = 0 ; chunkIndex < totalChunks ; chunkIndex ++ )
63- {
64- // Create chunk metadata
65- var metadata = chunkIndex == 0
66- ? ChunkMetadata . CreateFirstChunk ( messageId , totalChunks , checksum , _options . ChunkTimeout )
67- : ChunkMetadata . CreateSubsequentChunk ( messageId , chunkIndex , _options . ChunkTimeout ) ;
68-
69- // Serialize the metadata to JSON
70- var metadataJson = JsonSerializer . Serialize ( metadata ) ;
71-
72- // Create user properties for this chunk
73- var chunkUserProperties = new List < MqttUserProperty > ( userProperties )
74- {
75- // Add the chunk metadata property
76- new ( ChunkingConstants . ChunkUserProperty , metadataJson )
77- } ;
78-
79- // Extract the chunk payload
80- var chunkStart = ( long ) chunkIndex * maxChunkSize ;
81- var chunkLength = Math . Min ( maxChunkSize , payload . Length - chunkStart ) ;
82- var chunkPayload = payload . Slice ( chunkStart , chunkLength ) ;
83-
84- // Create a message for this chunk
85- var chunkMessage = new MqttApplicationMessage ( message . Topic , message . QualityOfServiceLevel )
86- {
87- Retain = message . Retain ,
88- Payload = chunkPayload ,
89- ContentType = message . ContentType ,
90- ResponseTopic = message . ResponseTopic ,
91- CorrelationData = message . CorrelationData ,
92- PayloadFormatIndicator = message . PayloadFormatIndicator ,
93- MessageExpiryInterval = message . MessageExpiryInterval ,
94- TopicAlias = message . TopicAlias ,
95- SubscriptionIdentifiers = message . SubscriptionIdentifiers ,
96- UserProperties = chunkUserProperties
97- } ;
98-
99- chunks . Add ( chunkMessage ) ;
100- }
83+ return ( payload , totalChunks , messageId , checksum , userProperties ) ;
84+ }
10185
102- return chunks ;
86+ private static ReadOnlySequence < byte > ExtractChunkPayload ( ReadOnlySequence < byte > payload , int chunkIndex , int maxChunkSize )
87+ {
88+ var chunkStart = ( long ) chunkIndex * maxChunkSize ;
89+ var chunkLength = Math . Min ( maxChunkSize , payload . Length - chunkStart ) ;
90+ return payload . Slice ( chunkStart , chunkLength ) ;
10391 }
10492
105- private int GetMaxChunkSize ( int maxPacketSize )
93+ private MqttApplicationMessage CreateChunk (
94+ MqttApplicationMessage originalMessage ,
95+ ReadOnlySequence < byte > chunkPayload ,
96+ List < MqttUserProperty > userProperties ,
97+ string messageId ,
98+ int chunkIndex ,
99+ int totalChunks ,
100+ string checksum )
106101 {
107- ArgumentOutOfRangeException . ThrowIfLessThanOrEqual ( maxPacketSize , _options . StaticOverhead ) ;
108- // Subtract the static overhead to ensure we don't exceed the broker's limits
109- return maxPacketSize - _options . StaticOverhead ;
102+ // Create chunk metadata
103+ var metadata = chunkIndex == 0
104+ ? ChunkMetadata . CreateFirstChunk ( messageId , totalChunks , checksum , _options . ChunkTimeout )
105+ : ChunkMetadata . CreateSubsequentChunk ( messageId , chunkIndex , _options . ChunkTimeout ) ;
106+
107+ // Serialize the metadata to JSON
108+ var metadataJson = JsonSerializer . Serialize ( metadata ) ;
109+
110+ // Create user properties for this chunk
111+ var chunkUserProperties = new List < MqttUserProperty > ( userProperties )
112+ {
113+ // Add the chunk metadata property
114+ new ( ChunkingConstants . ChunkUserProperty , metadataJson )
115+ } ;
116+
117+ // Create a message for this chunk
118+ return new MqttApplicationMessage ( originalMessage . Topic , originalMessage . QualityOfServiceLevel )
119+ {
120+ Retain = originalMessage . Retain ,
121+ Payload = chunkPayload ,
122+ ContentType = originalMessage . ContentType ,
123+ ResponseTopic = originalMessage . ResponseTopic ,
124+ CorrelationData = originalMessage . CorrelationData ,
125+ PayloadFormatIndicator = originalMessage . PayloadFormatIndicator ,
126+ MessageExpiryInterval = originalMessage . MessageExpiryInterval ,
127+ TopicAlias = originalMessage . TopicAlias ,
128+ SubscriptionIdentifiers = originalMessage . SubscriptionIdentifiers ,
129+ UserProperties = chunkUserProperties
130+ } ;
110131 }
111132}
0 commit comments