@@ -13,6 +13,21 @@ namespace BD.Common8.Http.ClientFactory.Services.Implementation;
1313/// </summary>
1414public class FusilladeClientHttpClientFactory : IClientHttpClientFactory , IDisposable
1515{
16+ internal static readonly global ::Microsoft . IO . RecyclableMemoryStreamManager MemoryStreamManager = new ( ) ;
17+
18+ internal static async Task < global ::Microsoft . IO . RecyclableMemoryStream > ReadAsStreamAsync ( HttpContent content , CancellationToken cancellationToken = default )
19+ {
20+ if ( content is RecyclableMemoryStreamContent streamContent )
21+ {
22+ return streamContent . Stream ;
23+ }
24+
25+ var stream = await content . ReadAsStreamAsync ( cancellationToken ) ;
26+ var memoryStream = MemoryStreamManager . GetStream ( ) ;
27+ await stream . CopyToAsync ( memoryStream , cancellationToken ) ;
28+ return memoryStream ;
29+ }
30+
1631 bool disposedValue ;
1732
1833 readonly HttpMessageHandler handler ;
@@ -301,7 +316,7 @@ static void Write(Stream s, IEnumerable<object> items)
301316 /// <returns>The unique key.</returns>
302317 public static string UniqueKeyForRequest ( HttpRequestMessage request )
303318 {
304- var requestUriString = ImageHttpClientServiceImpl . ImageHttpRequestMessage . GetOriginalRequestUri ( request ) ;
319+ var requestUriString = ImageHttpClientServiceImpl . GetOriginalRequestUri ( request ) ;
305320 return UniqueKeyForRequest ( requestUriString , request ) ;
306321 }
307322
@@ -385,32 +400,58 @@ protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage reques
385400
386401 if ( cacheResult != null && resp . Content != null )
387402 {
388- var ms = new MemoryStream ( ) ;
403+ using var ms = FusilladeClientHttpClientFactory . MemoryStreamManager . GetStream ( ) ;
389404#if NET5_0_OR_GREATER
390405 var stream = await resp . Content . ReadAsStreamAsync ( realToken . Token ) . ConfigureAwait ( false ) ;
391406#else
392407 var stream = await resp . Content . ReadAsStreamAsync ( ) . ConfigureAwait ( false ) ;
393408#endif
394- await stream . CopyToAsync ( ms , 32 * 1024 , realToken . Token ) . ConfigureAwait ( false ) ;
409+ await stream . CopyToAsync ( ms , realToken . Token ) . ConfigureAwait ( false ) ;
395410
396411 realToken . Token . ThrowIfCancellationRequested ( ) ;
397412
398- var newResp = new HttpResponseMessage ( ) ;
413+ var newResp = new HttpResponseMessage ( )
414+ {
415+ RequestMessage = request ,
416+ } ;
399417 foreach ( var kvp in resp . Headers )
400418 {
401419 newResp . Headers . TryAddWithoutValidation ( kvp . Key , kvp . Value ) ;
402420 }
403421
404- var newContent = new ByteArrayContent ( ms . ToArray ( ) ) ;
405- foreach ( var kvp in resp . Content . Headers )
422+ if ( request . RequestUri ? . ToString ( ) == "https://picsum.photos/360/202?image=883" )
406423 {
407- newContent . Headers . TryAddWithoutValidation ( kvp . Key , kvp . Value ) ;
424+ //TODO
408425 }
409426
410- newResp . Content = newContent ;
411-
427+ {
428+ var newContent = new RecyclableMemoryStreamContent ( ms ) ;
429+ foreach ( var kvp in resp . Content . Headers )
430+ {
431+ newContent . Headers . TryAddWithoutValidation ( kvp . Key , kvp . Value ) ;
432+ }
433+ newResp . Content = newContent ;
434+ }
412435 resp = newResp ;
413436 await cacheResult ( request , resp , key , realToken . Token ) . ConfigureAwait ( false ) ;
437+ if ( request . Options . TryGetValue ( IImageHttpClientService . KeyFilePath , out var filePath ) )
438+ {
439+ var newContent = new FileContent ( filePath ) ;
440+ foreach ( var kvp in resp . Content . Headers )
441+ {
442+ newContent . Headers . TryAddWithoutValidation ( kvp . Key , kvp . Value ) ;
443+ }
444+ newResp . Content = newContent ;
445+ }
446+ else
447+ {
448+ var newContent = new ByteArrayContent ( ms . GetBuffer ( ) ) ;
449+ foreach ( var kvp in resp . Content . Headers )
450+ {
451+ newContent . Headers . TryAddWithoutValidation ( kvp . Key , kvp . Value ) ;
452+ }
453+ newResp . Content = newContent ;
454+ }
414455 }
415456
416457 return resp ;
@@ -429,6 +470,53 @@ protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage reques
429470 }
430471}
431472
473+ file sealed class FileContent ( string filePath ) : HttpContent
474+ {
475+ protected override async Task SerializeToStreamAsync ( Stream stream , TransportContext ? context )
476+ {
477+ try
478+ {
479+ using var fileStream = new FileStream ( filePath , FileMode . Open , FileAccess . Read , FileShare . ReadWrite | FileShare . Delete ) ;
480+ await fileStream . CopyToAsync ( stream ) ;
481+ }
482+ catch ( DirectoryNotFoundException )
483+ {
484+ }
485+ catch ( FileNotFoundException )
486+ {
487+ }
488+ }
489+
490+ protected override bool TryComputeLength ( out long length )
491+ {
492+ try
493+ {
494+ length = new FileInfo ( filePath ) . Length ;
495+ return true ;
496+ }
497+ catch ( DirectoryNotFoundException )
498+ {
499+ }
500+ catch ( FileNotFoundException )
501+ {
502+ }
503+ length = 0 ;
504+ return false ;
505+ }
506+ }
507+
508+ file sealed class RecyclableMemoryStreamContent : StreamContent
509+ {
510+ readonly global ::Microsoft . IO . RecyclableMemoryStream stream ;
511+
512+ internal global ::Microsoft . IO . RecyclableMemoryStream Stream => stream ;
513+
514+ internal RecyclableMemoryStreamContent ( global ::Microsoft . IO . RecyclableMemoryStream stream ) : base ( stream )
515+ {
516+ this . stream = stream ;
517+ }
518+ }
519+
432520/// <summary>
433521/// A http handler that will make a response even if the HttpClient is offline.
434522/// </summary>
@@ -439,6 +527,8 @@ file sealed class OfflineHttpMessageHandler2() : HttpMessageHandler
439527{
440528 const HttpStatusCode OfflineCacheMiss = ( HttpStatusCode ) 599 ;
441529
530+ HttpResponseMessage ResponseOfflineCacheMiss ( ) => new ( OfflineCacheMiss ) ;
531+
442532 /// <inheritdoc />
443533 protected override async Task < HttpResponseMessage > SendAsync ( HttpRequestMessage request , CancellationToken cancellationToken )
444534 {
@@ -453,14 +543,40 @@ protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage
453543 throw new Exception ( "Configure NetCache.RequestCache before calling this!" ) ;
454544 }
455545
456- var body = await retrieveBody ( request , RateLimitedHttpMessageHandler2 . UniqueKeyForRequest ( request ) , cancellationToken ) . ConfigureAwait ( false ) ;
546+ var uniqueKey = RateLimitedHttpMessageHandler2 . UniqueKeyForRequest ( request ) ;
547+ var body = await retrieveBody ( request , uniqueKey , cancellationToken ) . ConfigureAwait ( false ) ;
457548 if ( body == null )
458549 {
459- return new HttpResponseMessage ( OfflineCacheMiss ) ;
550+ if ( request . Options . TryGetValue ( IImageHttpClientService . KeyFilePath , out var filePath ) )
551+ {
552+ if ( File . Exists ( filePath ) )
553+ {
554+ return new HttpResponseMessage ( HttpStatusCode . OK )
555+ {
556+ Content = new FileContent ( filePath ) ,
557+ } ;
558+ }
559+ else
560+ {
561+ return ResponseOfflineCacheMiss ( ) ;
562+ }
563+ }
564+ //else if (request.Options.TryGetValue(IImageHttpClientService.KeyStream, out var stream))
565+ //{
566+ // return new HttpResponseMessage(HttpStatusCode.OK)
567+ // {
568+ // Content = new StreamContent(stream),
569+ // };
570+ //}
571+ else
572+ {
573+ return ResponseOfflineCacheMiss ( ) ;
574+ }
460575 }
461-
462- var byteContent = new ByteArrayContent ( body ) ;
463- return new HttpResponseMessage ( HttpStatusCode . OK ) { Content = byteContent } ;
576+ return new HttpResponseMessage ( HttpStatusCode . OK )
577+ {
578+ Content = new ByteArrayContent ( body ) ,
579+ } ;
464580 }
465581}
466582#endif
0 commit comments