Skip to content

Commit

Permalink
Added FileCacheHandler
Browse files Browse the repository at this point in the history
  • Loading branch information
Kees committed Oct 14, 2023
1 parent f50b5af commit 014b4e9
Show file tree
Hide file tree
Showing 3 changed files with 130 additions and 76 deletions.
11 changes: 6 additions & 5 deletions ChromiumHtmlToPdfLib/ChromiumHtmlToPdfLib.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@

<PropertyGroup>
<TargetFrameworks>netcoreapp3.1;netstandard2.0</TargetFrameworks>
<Version>3.1.6</Version>
<Version>4.0.0</Version>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<Description>ChromiumHtmlToPdf is a 100% managed C# library that can be used to convert HTML to PDF or PNG format with the use of Google Chrome or Microsoft Edge</Description>
<Copyright>(C)2017-2023 Kees van Spelde</Copyright>
<PackageReleaseNotes>- Updated nuget packages
- Catch exception when one is thrown from the HTMLSanitizer</PackageReleaseNotes>
<PackageReleaseNotes>- Made code async from top to bottom (so make sure you test this)
- Implemented new file cache for document helper class
- Updated nuget packages</PackageReleaseNotes>
<PackageProjectUrl>https://github.com/Sicos1977/ChromiumHtmlToPdf</PackageProjectUrl>
<RepositoryUrl>https://github.com/Sicos1977/ChromiumHtmlToPdf</RepositoryUrl>
<RepositoryType>git</RepositoryType>
Expand All @@ -20,8 +21,8 @@
<Company>Magic-Sessions</Company>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>ChromiumHtmlToPdf.snk</AssemblyOriginatorKeyFile>
<AssemblyVersion>3.1.6.0</AssemblyVersion>
<FileVersion>3.1.6.0</FileVersion>
<AssemblyVersion>4.0.0.0</AssemblyVersion>
<FileVersion>4.0.0.0</FileVersion>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<DocumentationFile>bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml</DocumentationFile>
<PackageReadmeFile>README.md</PackageReadmeFile>
Expand Down
81 changes: 10 additions & 71 deletions ChromiumHtmlToPdfLib/Helpers/DocumentHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,32 +81,12 @@ internal class DocumentHelper : IDisposable
/// </summary>
private readonly WebProxy _webProxy;

/// <summary>
/// When <c>true</c> then caching is enabled
/// </summary>
private readonly bool _useCache;

/// <summary>
/// Used when mediaTimeout is set
/// </summary>
private readonly Stopwatch _stopwatch;

private readonly int _imageLoadTimeout;

/// <summary>
/// The cache folder
/// </summary>
private DirectoryInfo _cacheDirectory;

/// <summary>
/// The cache size
/// </summary>
private readonly long _cacheSize;

/// <summary>
/// <see cref="FileCache"/>
/// </summary>
private FileCache _fileCache;
#endregion

#region Properties
Expand Down Expand Up @@ -139,35 +119,6 @@ internal int TimeLeft
return (int)result;
}
}

/// <summary>
/// Returns a file cache
/// </summary>
private FileCache FileCache
{
get
{
if (_fileCache != null)
return _fileCache;

_cacheDirectory = new DirectoryInfo(Path.Combine("d:\\", "HttpClientHandler"));
//_cacheDirectory = new DirectoryInfo(Path.Combine(_cacheDirectory.FullName, "HttpClientHandler"));

if (!_cacheDirectory.Exists)
_cacheDirectory.Create();

FileCache.DefaultCacheManager = FileCacheManagers.Hashed;

_fileCache = new FileCache(_cacheDirectory.FullName)
{
MaxCacheSize = _cacheSize,
AccessTimeout = TimeSpan.FromSeconds(10),
DefaultPolicy = new CacheItemPolicy { SlidingExpiration = TimeSpan.FromDays(1) },
};

return _fileCache;
}
}
#endregion

#region Constructor
Expand All @@ -190,18 +141,13 @@ public DocumentHelper(DirectoryInfo tempDirectory,
ILogger logger)
{
_tempDirectory = tempDirectory;
_useCache = useCache;

if (useCache)
{
_cacheDirectory = cacheDirectory;
WriteToLog($"Setting cache directory to '{_cacheDirectory.FullName}' with a size of {cacheSize}");
_cacheSize = cacheSize;
}

_webProxy = webProxy;
_logger = logger;

if (useCache)
WriteToLog($"Setting cache directory to '{cacheDirectory.FullName}' with a size of {cacheSize} bytes");

if (!imageLoadTimeout.HasValue) return;
_imageLoadTimeout = imageLoadTimeout.Value;
WriteToLog($"Setting image load timeout to '{_imageLoadTimeout}' milliseconds");
Expand Down Expand Up @@ -542,9 +488,7 @@ public async Task<ValidateImagesResult> ValidateImagesAsync(
.WithCss();
}
else
{
config = Configuration.Default.WithCss();
}

var context = BrowsingContext.New(config);

Expand Down Expand Up @@ -646,7 +590,7 @@ public async Task<ValidateImagesResult> ValidateImagesAsync(
}
catch (Exception exception)
{
WriteToLog( $"Could not get computed style from html image, exception: '{exception.Message}'");
WriteToLog($"Could not get computed style from html image, exception: '{exception.Message}'");
}

if (style != null)
Expand Down Expand Up @@ -742,8 +686,7 @@ public async Task<ValidateImagesResult> ValidateImagesAsync(
using var textWriter = new StreamWriter(fileStream);
document.ToHtml(textWriter, new HtmlMarkupFormatter());
}



WriteToLog("Changed webpage written");

return new ValidateImagesResult(true, outputUri);
Expand Down Expand Up @@ -953,15 +896,13 @@ private async Task<Stream> OpenDownloadStream(Uri sourceUri, bool checkTimeout =
{
if (_useCache)
{
var item = FileCache.GetCacheItem(sourceUri.ToString());
if (item is { Value: not null })
{
WriteToLog($"Returning stream for url '{sourceUri}' from the cache");
return new MemoryStream((byte[])item.Value);
}
}

var request = WebRequest.CreateHttp(sourceUri);

if (_webProxy != null)
request.Proxy = _webProxy;

var timeLeft = TimeLeft;

if (_stopwatch != null && checkTimeout)
Expand All @@ -975,13 +916,11 @@ private async Task<Stream> OpenDownloadStream(Uri sourceUri, bool checkTimeout =
request.Timeout = TimeLeft;
}


WriteToLog($"Opening stream to url '{sourceUri}'{(_stopwatch != null ? $" with a timeout of {timeLeft} milliseconds" : string.Empty)}");

var response = await request.GetResponseAsync();

if (!_useCache)
return response.GetResponseStream();

var stream = response.GetResponseStream();

if (stream == null)
Expand Down
114 changes: 114 additions & 0 deletions ChromiumHtmlToPdfLib/Helpers/FileCacheHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
using System;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Runtime.Caching;
using System.Threading;
using System.Threading.Tasks;

namespace ChromiumHtmlToPdfLib.Helpers;

/// <summary>
/// An <see cref="HttpClientHandler"/> that caches the response when requested
/// </summary>
internal class FileCacheHandler : HttpClientHandler
{
#region Properties
/// <summary>
/// When <c>true</c> then caching is enabled
/// </summary>
private readonly bool _useCache;

/// <summary>
/// The cache folder
/// </summary>
private DirectoryInfo _cacheDirectory;

/// <summary>
/// The cache size
/// </summary>
private readonly long _cacheSize;

/// <summary>
/// <see cref="FileCache"/>
/// </summary>
private FileCache _fileCache;
#endregion

#region Properties
/// <summary>
/// Returns <c>true</c> when the response is from the cache
/// </summary>
internal bool IsFromCache { get; set; }

/// <summary>
/// Returns a file cache
/// </summary>
private FileCache FileCache
{
get
{
if (_fileCache != null)
return _fileCache;

//_cacheDirectory = new DirectoryInfo(Path.Combine("d:\\", "HttpClientHandler"));
_cacheDirectory = new DirectoryInfo(Path.Combine(_cacheDirectory.FullName, "HttpClientHandler"));

if (!_cacheDirectory.Exists)
_cacheDirectory.Create();

FileCache.DefaultCacheManager = FileCacheManagers.Hashed;

_fileCache = new FileCache(_cacheDirectory.FullName)
{
MaxCacheSize = _cacheSize,
AccessTimeout = TimeSpan.FromSeconds(10),
DefaultPolicy = new CacheItemPolicy { SlidingExpiration = TimeSpan.FromDays(1) },
};

return _fileCache;
}
}
#endregion

#region Constructor
internal FileCacheHandler(bool useCache, FileSystemInfo cacheDirectory, long cacheSize)
{
_useCache = useCache;
if (!useCache) return;
_cacheDirectory = new DirectoryInfo(Path.Combine(cacheDirectory.FullName, "HttpClientHandler"));
_cacheSize = cacheSize;
}
#endregion

#region SendAsync
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
if (!_useCache)
return base.SendAsync(request, cancellationToken);

var key = request.RequestUri.ToString();
var item = FileCache.GetCacheItem(key);

if (item is { Value: not null })
{
var cachedResponse = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StreamContent(new MemoryStream((byte[])item.Value)),
ReasonPhrase = "Loaded from cache"
};

return Task.FromResult(cachedResponse);
}

var response = base.SendAsync(request, cancellationToken).Result;
var memoryStream = new MemoryStream();
response.Content.ReadAsStreamAsync().GetAwaiter().GetResult().CopyTo(memoryStream);
//WriteToLog($"Adding item from url '{sourceUri}' to the cache");
FileCache.Add(key, memoryStream.ToArray(), new CacheItemPolicy { SlidingExpiration = TimeSpan.FromDays(1) });
response.Content = new StreamContent(new MemoryStream(memoryStream.ToArray()));

return Task.FromResult(response);
}
#endregion
}

0 comments on commit 014b4e9

Please sign in to comment.