Skip to content

Commit

Permalink
optimize rule providers
Browse files Browse the repository at this point in the history
  • Loading branch information
tinohager committed Feb 15, 2024
1 parent 397f803 commit 3ec24ca
Show file tree
Hide file tree
Showing 7 changed files with 160 additions and 20 deletions.
6 changes: 3 additions & 3 deletions src/Nager.PublicSuffix.TestConsole/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Nager.PublicSuffix;
using Nager.PublicSuffix.CacheProviders;
using Nager.PublicSuffix.RuleProviders;
using Nager.PublicSuffix.RuleProviders.CacheProviders;

using var loggerFactory = LoggerFactory.Create(builder =>
{
builder.AddConsole();
});

var logger = loggerFactory.CreateLogger("Program");
var ruleProviderLogger = loggerFactory.CreateLogger<WebRuleProvider>();
var ruleProviderLogger = loggerFactory.CreateLogger<CachedHttpRuleProvider>();

IConfiguration configuration = new ConfigurationBuilder()
.AddInMemoryCollection(new List<KeyValuePair<string, string?>>
Expand All @@ -23,7 +23,7 @@
var httpClient = new HttpClient();
var cacheProvider = new LocalFileSystemCacheProvider();

var ruleProvider = new WebRuleProvider(ruleProviderLogger, configuration, cacheProvider, httpClient);
var ruleProvider = new CachedHttpRuleProvider(ruleProviderLogger, configuration, cacheProvider, httpClient);
await ruleProvider.BuildAsync(ignoreCache: true);

//var ruleProvider = new LocalFileRuleProvider("public_suffix_list.dat");
Expand Down
6 changes: 3 additions & 3 deletions src/Nager.PublicSuffix.UnitTest/RuleProviderTest.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using Microsoft.Extensions.Configuration;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Nager.PublicSuffix.CacheProviders;
using Nager.PublicSuffix.RuleProviders;
using Nager.PublicSuffix.RuleProviders.CacheProviders;
using Nager.PublicSuffix.UnitTest.Helpers;
using System.Net.Http;
using System.Threading.Tasks;
Expand All @@ -14,15 +14,15 @@ public class RuleProviderTest
[TestMethod]
public async Task WebTldRuleProviderTest()
{
var loggerMock = LoggerHelper.GetLogger<WebRuleProvider>();
var loggerMock = LoggerHelper.GetLogger<CachedHttpRuleProvider>();

var builder = new ConfigurationBuilder();
using var httpClient = new HttpClient();

var configuration = builder.Build();

var cacheProvider = new LocalFileSystemCacheProvider();
var webRuleProvider = new WebRuleProvider(loggerMock.Object, configuration, cacheProvider, httpClient);
var webRuleProvider = new CachedHttpRuleProvider(loggerMock.Object, configuration, cacheProvider, httpClient);
var domainDataStructure = await webRuleProvider.BuildAsync();
Assert.IsNotNull(domainDataStructure);
}
Expand Down
4 changes: 2 additions & 2 deletions src/Nager.PublicSuffix.WebApi/Program.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using Nager.PublicSuffix;
using Nager.PublicSuffix.CacheProviders;
using Nager.PublicSuffix.RuleProviders;
using Nager.PublicSuffix.RuleProviders.CacheProviders;
using Nager.PublicSuffix.WebApi.Models;
using System.Text.Encodings.Web;
using System.Text.Json.Serialization;
Expand All @@ -12,7 +12,7 @@

builder.Services.AddHttpClient();
builder.Services.AddSingleton<ICacheProvider, LocalFileSystemCacheProvider>();
builder.Services.AddSingleton<IRuleProvider, WebRuleProvider>();
builder.Services.AddSingleton<IRuleProvider, CachedHttpRuleProvider>();
builder.Services.AddSingleton<IDomainParser, DomainParser>();

// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System.Threading.Tasks;

namespace Nager.PublicSuffix.CacheProviders
namespace Nager.PublicSuffix.RuleProviders.CacheProviders
{
/// <summary>
/// ICacheProvider
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
using System.IO;
using System.Threading.Tasks;

namespace Nager.PublicSuffix.CacheProviders
namespace Nager.PublicSuffix.RuleProviders.CacheProviders
{
/// <summary>
/// LocalFileSystemCacheProvider, write the data to a cache file in the temp directory
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Nager.PublicSuffix.CacheProviders;
using Nager.PublicSuffix.Exceptions;
using Nager.PublicSuffix.Extensions;
using Nager.PublicSuffix.Models;
using Nager.PublicSuffix.RuleParsers;
using Nager.PublicSuffix.RuleProviders.CacheProviders;
using System;
using System.Net.Http;
using System.Threading;
Expand All @@ -13,12 +13,12 @@
namespace Nager.PublicSuffix.RuleProviders
{
/// <summary>
/// Web RuleProvider
/// CachedHttp RuleProvider
/// </summary>
public class WebRuleProvider : IRuleProvider
public class CachedHttpRuleProvider : IRuleProvider
{
private readonly string _dataFileUrl;
private readonly ILogger<WebRuleProvider> _logger;
private readonly ILogger<CachedHttpRuleProvider> _logger;
private readonly ICacheProvider _cacheProvider;
private readonly HttpClient _httpClient;
private DomainDataStructure? _domainDataStructure;
Expand All @@ -29,16 +29,16 @@ public class WebRuleProvider : IRuleProvider
public ICacheProvider CacheProvider { get { return this._cacheProvider; } }

/// <summary>
/// Web RuleProvider<br/>
/// Loads the public suffix definition file from the official website
/// CachedHttp RuleProvider<br/>
/// Loads the public suffix definition file from the official website and use a local cache for quicker initialization
/// </summary>
/// <remarks>It is possible to overwrite the url via configuration parameters <c>Nager:PublicSuffix:DataUrl</c></remarks>
/// <param name="logger"></param>
/// <param name="configuration"></param>
/// <param name="cacheProvider"></param>
/// <param name="httpClient"></param>
public WebRuleProvider(
ILogger<WebRuleProvider> logger,
public CachedHttpRuleProvider(
ILogger<CachedHttpRuleProvider> logger,
IConfiguration configuration,
ICacheProvider cacheProvider,
HttpClient httpClient
Expand All @@ -62,8 +62,6 @@ public async Task<bool> BuildAsync(
bool ignoreCache = false,
CancellationToken cancellationToken = default)
{
var ruleParser = new TldRuleParser();

string? ruleData;
if (this._cacheProvider.IsCacheValid() && ignoreCache == false)
{
Expand Down Expand Up @@ -92,6 +90,7 @@ public async Task<bool> BuildAsync(
return false;
}

var ruleParser = new TldRuleParser();
var rules = ruleParser.ParseRules(ruleData);

var domainDataStructure = new DomainDataStructure("*", new TldRule("*"));
Expand Down
141 changes: 141 additions & 0 deletions src/Nager.PublicSuffix/RuleProviders/SimpleHttpRuleProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Nager.PublicSuffix.Exceptions;
using Nager.PublicSuffix.Extensions;
using Nager.PublicSuffix.Models;
using Nager.PublicSuffix.RuleParsers;
using System;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;

namespace Nager.PublicSuffix.RuleProviders
{
/// <summary>
/// Simple Http RuleProvider
/// </summary>
public class SimpleHttpRuleProvider : IRuleProvider, IDisposable
{
private bool _disposed;
private readonly string _dataFileUrl;
private readonly ILogger<SimpleHttpRuleProvider> _logger;
private readonly HttpClient _httpClient;
private readonly bool _disposeHttpClient;
private DomainDataStructure? _domainDataStructure;

/// <summary>
/// Simple Http RuleProvider<br/>
/// Loads the public suffix definition file from the official website
/// </summary>
/// <remarks>It is possible to overwrite the url via configuration parameters <c>Nager:PublicSuffix:DataUrl</c></remarks>
/// <param name="configuration"></param>
/// <param name="httpClient"></param>
/// <param name="logger"></param>
public SimpleHttpRuleProvider(
IConfiguration configuration,
HttpClient? httpClient = null,
ILogger<SimpleHttpRuleProvider>? logger = null)
{
this._logger = logger ?? new NullLogger<SimpleHttpRuleProvider>();

this._disposeHttpClient = httpClient == null;
this._httpClient = httpClient ?? new HttpClient();

var url = configuration["Nager:PublicSuffix:DataUrl"];
if (string.IsNullOrEmpty(url))
{
url = "https://publicsuffix.org/list/public_suffix_list.dat";
}

this._dataFileUrl = url;
}

/// <inheritdoc/>
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}

/// <inheritdoc/>
protected virtual void Dispose(bool disposing)
{
if (this._disposed)
{
return;
}

if (disposing)
{
if (this._disposeHttpClient)
{
this._httpClient.Dispose();
}
}

this._disposed = true;
}

/// <inheritdoc/>
public async Task<bool> BuildAsync(
bool ignoreCache = false,
CancellationToken cancellationToken = default)
{
string? ruleData;

this._logger.LogInformation($"{nameof(BuildAsync)} - Start downloading data from url");

try
{
ruleData = await this.LoadFromUrlAsync(this._dataFileUrl, cancellationToken).ConfigureAwait(false);
}
catch (Exception exception)
{
this._logger.LogError(exception, $"{nameof(BuildAsync)} - Failure on download");

return false;
}

if (string.IsNullOrEmpty(ruleData))
{
return false;
}

var ruleParser = new TldRuleParser();
var rules = ruleParser.ParseRules(ruleData);

var domainDataStructure = new DomainDataStructure("*", new TldRule("*"));
domainDataStructure.AddRules(rules);

this._domainDataStructure = domainDataStructure;

return true;
}

/// <inheritdoc/>
public DomainDataStructure? GetDomainDataStructure()
{
return this._domainDataStructure;
}

/// <summary>
/// Load the public suffix data from the given url
/// </summary>
/// <param name="url"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public async Task<string> LoadFromUrlAsync(
string url,
CancellationToken cancellationToken)
{
using var response = await this._httpClient.GetAsync(url, cancellationToken).ConfigureAwait(false);
if (!response.IsSuccessStatusCode)
{
throw new RuleLoadException($"Cannot load file from {url} StatusCode:{(int)response.StatusCode}");
}

return await response.Content.ReadAsStringAsync().ConfigureAwait(false);
}
}
}

0 comments on commit 3ec24ca

Please sign in to comment.