11using System ;
22using System . Collections . Generic ;
3+ using System . IO ;
34using System . Linq ;
45using System . Net . Http ;
56using System . Text ;
@@ -27,7 +28,7 @@ public MatterhookClient(string webhookUrl, int timeoutSeconds = 100)
2728 _httpClient . Timeout = new TimeSpan ( 0 , 0 , 0 , timeoutSeconds ) ;
2829 }
2930
30- public MattermostMessage CloneMessage ( MattermostMessage inMsg )
31+ private MattermostMessage CloneMessage ( MattermostMessage inMsg )
3132 {
3233 var outMsg = new MattermostMessage
3334 {
@@ -61,95 +62,83 @@ private static MattermostAttachment CloneAttachment(MattermostAttachment inAtt)
6162 }
6263
6364 /// <summary>
64- /// Post Message to Mattermost server. Messages will be automatically split if total text length > 4000
65+ /// Post Message to Mattermost server. Messages will be automatically split. (Mattermost actually already auto splits long messages, but this will preserve whole words, rather than just splitting on message length alone.
6566 /// </summary>
6667 /// <param name="inMessage">The messsage you wish to send</param>
67- /// <param name="maxMessageLength">(Optional) Defaulted to 3800 , but can be set to any value (Check with your Mattermost server admin!)</param>
68+ /// <param name="maxMessageLength">(Optional) Defaulted to 4000 , but can be set to any value (Check with your Mattermost server admin!)</param>
6869 /// <returns></returns>
69- public async Task < HttpResponseMessage > PostAsync ( MattermostMessage inMessage , int maxMessageLength = 3800 )
70+ public async Task < HttpResponseMessage > PostAsync ( MattermostMessage inMessage , int maxMessageLength = 4000 )
7071 {
71-
7272 try
7373 {
7474 HttpResponseMessage response = null ;
75- var outMessages = new List < MattermostMessage > ( ) ;
7675
77- var msgCount = 0 ;
76+ maxMessageLength -= 10 ; //To allow for adding a message number indicator at the front end of the message.
7877
79- var lines = new string [ ] { } ;
80- if ( inMessage . Text != null )
78+ var outMessages = new List < MattermostMessage >
8179 {
82- lines = inMessage . Text . Split ( new [ ] { " \r \n " , " \r " , " \n " } , StringSplitOptions . None ) ;
83- }
80+ CloneMessage ( inMessage )
81+ } ;
8482
85- //start with one cloned inMessage in the list
86- outMessages . Add ( CloneMessage ( inMessage ) ) ;
83+ var msgIdx = 0 ;
8784
88- //add text from original. If we go over 3800 (or whatever user chooses), we'll split it to a new inMessage.
89- foreach ( var line in lines )
85+ if ( inMessage . Text != null )
9086 {
87+ //Split messages text into chunks of maxMessageLength in size.
88+ var textChunks = SplitTextIntoChunks ( inMessage . Text , maxMessageLength ) ;
9189
92- if ( line . Length + outMessages [ msgCount ] . Text . Length > maxMessageLength )
90+ //iterate through chunks and create a MattermostMessage object for each one and add it to outMessages list.
91+ foreach ( var chunk in textChunks )
9392 {
94-
95- msgCount += 1 ;
96- outMessages . Add ( CloneMessage ( inMessage ) ) ;
93+ outMessages [ msgIdx ] . Text = chunk ;
94+ if ( msgIdx < textChunks . Count ( ) - 1 )
95+ {
96+ outMessages . Add ( CloneMessage ( inMessage ) ) ;
97+ msgIdx ++ ;
98+ }
9799 }
100+ }
98101
99- outMessages [ msgCount ] . Text += $ "{ line } \r \n ";
100- }
101-
102- //Length of text on the last (or first if only one) inMessage.
103- var lenMessageText = outMessages [ msgCount ] . Text . Length ;
104-
105- //does our original have attachments?
106- if ( inMessage . Attachments ? . Any ( ) ?? false )
107- {
108- outMessages [ msgCount ] . Attachments = new List < MattermostAttachment > ( ) ;
109-
110- //loop through them in a similar fashion to the inMessage text above.
111- foreach ( var att in inMessage . Attachments )
102+ //next check for attachments on the original message object
103+ if ( inMessage . Attachments . Any ( ) )
112104 {
113- //add this attachment to the outgoing message
114- outMessages [ msgCount ] . Attachments . Add ( CloneAttachment ( att ) ) ;
115- //get a count of attachments on this message, and subtract one so we know the index of the current new attachment
116- var attIndex = outMessages [ msgCount ] . Attachments . Count - 1 ;
105+ outMessages [ msgIdx ] . Attachments = new List < MattermostAttachment > ( ) ;
106+ var msgCnt = msgIdx ;
117107
118- //Get the text lines
119- lines = att . Text . Split ( new [ ] { "\r \n " , "\r " , "\n " } , StringSplitOptions . None ) ;
120-
121- foreach ( var line in lines )
108+ foreach ( var att in inMessage . Attachments )
122109 {
123- //Get the total length of all attachments on the current outgoing message
124- var lenAllAttsText = outMessages [ msgCount ] . Attachments . Sum ( a => a . Text . Length ) ;
110+ outMessages [ msgIdx ] . Attachments . Add ( CloneAttachment ( att ) ) ;
111+ var attIdx = outMessages [ msgIdx ] . Attachments . Count - 1 ;
112+
113+ var attTextChunks = SplitTextIntoChunks ( att . Text , 6600 ) ; //arbitrary limit. MM files suggest limit is 7600, but that still results in attachments being truncated...
125114
126- if ( lenMessageText + lenAllAttsText + line . Length > maxMessageLength )
115+ foreach ( var attChunk in attTextChunks )
127116 {
128- msgCount += 1 ;
129- attIndex = 0 ;
130- outMessages . Add ( CloneMessage ( inMessage ) ) ;
131- outMessages [ msgCount ] . Attachments = new List < MattermostAttachment > { CloneAttachment ( att ) } ;
117+ outMessages [ msgIdx ] . Attachments [ attIdx ] . Text = attChunk ;
118+
119+ if ( msgIdx < msgCnt + attTextChunks . Count ( ) - 1 )
120+ {
121+ outMessages . Add ( CloneMessage ( inMessage ) ) ;
122+ msgIdx ++ ;
123+ outMessages [ msgIdx ] . Attachments = new List < MattermostAttachment > { CloneAttachment ( att ) } ;
124+ }
132125 }
133-
134- outMessages [ msgCount ] . Attachments [ attIndex ] . Text += $ "{ line } \r \n ";
135126 }
136127 }
137- }
138-
139128
140129 if ( outMessages . Count > 1 )
141130 {
142131 var num = 1 ;
143132 foreach ( var msg in outMessages )
144133 {
145- msg . Text = $ "`({ num } /{ msgCount + 1 } ): ` " + msg . Text ;
134+ msg . Text = $ "`({ num } /{ msgIdx + 1 } ): ` " + msg . Text ;
146135 num ++ ;
147136 }
148137 }
149138
150139 foreach ( var msg in outMessages )
151140 {
152- var serializedPayload = JsonConvert . SerializeObject ( msg ) ;
141+ var serializedPayload = JsonConvert . SerializeObject ( msg ) ;
153142 response = await _httpClient . PostAsync ( _webhookUrl ,
154143 new StringContent ( serializedPayload , Encoding . UTF8 , "application/json" ) ) ;
155144 }
@@ -163,5 +152,38 @@ public async Task<HttpResponseMessage> PostAsync(MattermostMessage inMessage, in
163152 throw ;
164153 }
165154 }
155+
156+ private static IEnumerable < string > SplitTextIntoChunks ( string str , int maxChunkSize , bool preserveWords = true )
157+ {
158+
159+ if ( preserveWords )
160+ {
161+ //Less Simple
162+ var words = str . Split ( ' ' ) ;
163+ var tempString = new StringBuilder ( "" ) ;
164+
165+ foreach ( var word in words )
166+ {
167+ if ( word . Length + tempString . Length + 1 > maxChunkSize )
168+ {
169+ yield return tempString . ToString ( ) ;
170+ tempString . Clear ( ) ;
171+ }
172+
173+ tempString . Append ( tempString . Length > 0 ? " " + word : word ) ;
174+ }
175+
176+ yield return tempString . ToString ( ) ;
177+ }
178+ else
179+ {
180+ //Simple
181+ for ( var i = 0 ; i < str . Length ; i += maxChunkSize )
182+ {
183+ yield return str . Substring ( i , Math . Min ( maxChunkSize , str . Length - i ) ) ;
184+ }
185+ }
186+
187+ }
166188 }
167189}
0 commit comments