66using System . Linq ;
77using System . Net ;
88using System . Net . Http ;
9+ using System . Text ;
910using System . Text . RegularExpressions ;
1011using System . Threading ;
1112using System . Threading . Tasks ;
@@ -31,16 +32,17 @@ public struct Attachment
3132 internal readonly string _id ;
3233
3334 /// <summary>
34- /// Get the content of the attachment as stream
35+ /// Get the content of the attachment as stream with a progress report
3536 /// </summary>
3637 /// <param name="client">The client with them you got this instane (It doesn't have to be the same client but the same account)</param>
3738 /// <param name="timeout">The time after that the download of the content will cancelled (In miliseconds)</param>
39+ /// <param name="progress">The progress of the download in percent</param>
3840 /// <param name="ct">Cancellation token</param>
3941 /// <returns>The attachment as stream</returns>
4042 /// <exception cref="ObjectDisposedException">Thrown when the instance was disposed</exception>
4143 /// <exception cref="UnauthorizedAccessException">Thrown when you're logged in</exception>
4244 /// <exception cref="HttpRequestException">Thrown when an error happened while the http request</exception>
43- public async Task < Stream > DownloadContentAsStreamAsync ( WebUntisClient client , int timeout = 2000 , CancellationToken ct = default )
45+ public async Task < Stream > DownloadContentAsStreamAsync ( WebUntisClient client , TimeSpan timeout , IProgress < double > progress = null , CancellationToken ct = default )
4446 {
4547 string storageResponseString = await client . MakeAPIGetRequestAsync ( $ "/WebUntis/api/rest/view/v1/messages/{ _id } /attachmentstorageurl", ct ) ;
4648
@@ -64,24 +66,44 @@ public async Task<Stream> DownloadContentAsStreamAsync(WebUntisClient client, in
6466
6567 using ( HttpClient downloadClient = new HttpClient ( ) )
6668 {
67- downloadClient . Timeout = TimeSpan . FromMilliseconds ( timeout ) ;
68- HttpResponseMessage response = await downloadClient . SendAsync ( request , ct ) ;
69+ downloadClient . Timeout = timeout ;
70+ HttpResponseMessage response = await downloadClient . SendAsync ( request , HttpCompletionOption . ResponseHeadersRead , ct ) ;
6971
70- // Check cancellation token
71- if ( ct . IsCancellationRequested )
72- return default ;
72+ using ( MemoryStream content = new MemoryStream ( ) )
73+ {
74+ using ( Stream contentStream = await response . Content . ReadAsStreamAsync ( ) )
75+ {
76+ int totalBytes = ( int ? ) response . Content . Headers . ContentLength ?? - 1 ;
77+ int totalRecievedBytes = 0 ;
7378
74- // Verify response
75- if ( response . StatusCode != HttpStatusCode . OK )
76- throw new HttpRequestException ( $ "There was an error while the http request (Code: { response . StatusCode } ).") ;
79+ int bytesRead = 0 ;
80+ byte [ ] buffer = new byte [ 8192 ] ;
81+ while ( ( bytesRead = await contentStream . ReadAsync ( buffer , 0 , buffer . Length , ct ) ) > 0 )
82+ {
83+ if ( ct . IsCancellationRequested )
84+ return default ;
7785
78- if ( response . StatusCode == HttpStatusCode . Unauthorized || response . StatusCode == HttpStatusCode . Forbidden )
79- {
80- string detail = Regex . Match ( await response . Content . ReadAsStringAsync ( ) , @"<Message>([a-zA-z0-9\s]+)</Message>" ) . Groups [ 1 ] . Value ; // Get the error message
81- throw new UnauthorizedAccessException ( $ "Invalid authentication. Detail: { detail } ") ;
82- }
86+ content . Write ( buffer , 0 , bytesRead ) ;
87+ totalRecievedBytes += bytesRead ;
88+ progress . Report ( ( double ) totalRecievedBytes / totalBytes * 100d ) ;
89+ }
90+ }
91+
92+ if ( ct . IsCancellationRequested )
93+ return default ;
8394
84- return await response . Content . ReadAsStreamAsync ( ) ;
95+ // Verify response
96+ if ( response . StatusCode == HttpStatusCode . Unauthorized || response . StatusCode == HttpStatusCode . Forbidden )
97+ {
98+ string detail = Regex . Match ( Encoding . UTF8 . GetString ( content . ToArray ( ) ) , @"<Message>([a-zA-z0-9\s]+)</Message>" ) . Groups [ 1 ] . Value ; // Get the error message
99+ throw new UnauthorizedAccessException ( $ "Invalid authentication. Detail: { detail } ") ;
100+ }
101+
102+ if ( response . StatusCode != HttpStatusCode . OK )
103+ throw new HttpRequestException ( $ "There was an error while the http request (Code: { response . StatusCode } ).") ;
104+
105+ return content ;
106+ }
85107 }
86108 }
87109 }
0 commit comments