From 480a2245c0f4e1f4753c92b9e29f8263851db7d6 Mon Sep 17 00:00:00 2001 From: "Collin M. Barrett" Date: Mon, 1 Jul 2019 14:42:50 -0500 Subject: [PATCH] further support for url validation --- .../Features/Urls/ValidateAllUrls.cs | 39 +++++++++ .../Features/Urls/ValidateUrls.cs | 83 +++++++++++++++---- src/FilterLists.Agent/Program.cs | 2 +- 3 files changed, 107 insertions(+), 17 deletions(-) create mode 100644 src/FilterLists.Agent/Features/Urls/ValidateAllUrls.cs diff --git a/src/FilterLists.Agent/Features/Urls/ValidateAllUrls.cs b/src/FilterLists.Agent/Features/Urls/ValidateAllUrls.cs new file mode 100644 index 000000000..ff65af667 --- /dev/null +++ b/src/FilterLists.Agent/Features/Urls/ValidateAllUrls.cs @@ -0,0 +1,39 @@ +using System.Threading; +using System.Threading.Tasks; +using FilterLists.Agent.Core.Entities; +using FilterLists.Agent.Core.Interfaces; +using MediatR; + +namespace FilterLists.Agent.Features.Urls +{ + public static class ValidateAllUrls + { + public class Command : IRequest + { + } + + public class Handler : AsyncRequestHandler + { + private readonly IMediator _mediator; + private readonly IUrlsRepository _repo; + + public Handler(IMediator mediator, IUrlsRepository urlsRepository) + { + _mediator = mediator; + _repo = urlsRepository; + } + + protected override async Task Handle(Command request, CancellationToken cancellationToken) + { + var maintainerUrls = await _repo.GetAllAsync(); + var errors = await _mediator.Send(new ValidateUrls.Command(maintainerUrls), cancellationToken); + + //TODO: validate if http can be changed to https + + //TODO: iterate through each IEntityUrl impl + + //TODO: create or edit GitHub issue with results + } + } + } +} \ No newline at end of file diff --git a/src/FilterLists.Agent/Features/Urls/ValidateUrls.cs b/src/FilterLists.Agent/Features/Urls/ValidateUrls.cs index f44325605..9721e1619 100644 --- a/src/FilterLists.Agent/Features/Urls/ValidateUrls.cs +++ b/src/FilterLists.Agent/Features/Urls/ValidateUrls.cs @@ -1,33 +1,84 @@ using System; +using System.Collections.Generic; +using System.Net.Http; using System.Threading; using System.Threading.Tasks; -using FilterLists.Agent.Core.Entities; -using FilterLists.Agent.Core.Interfaces; +using System.Threading.Tasks.Dataflow; +using FilterLists.Agent.Infrastructure.Clients; using MediatR; +using Microsoft.Extensions.Logging; namespace FilterLists.Agent.Features.Urls { public static class ValidateUrls { - public class Command : IRequest + public class Command : IRequest> { - } - - public class Handler : AsyncRequestHandler - { - private readonly IMediator _mediator; - private readonly IUrlsRepository _repo; - - public Handler(IMediator mediator, IUrlsRepository urlsRepository) + public Command(IEnumerable urls) { - _mediator = mediator; - _repo = urlsRepository; + Urls = urls; } - protected override async Task Handle(Command request, CancellationToken cancellationToken) + public IEnumerable Urls { get; } + } + + public class Handler : IRequestHandler> + { + private const int MaxDegreeOfParallelism = 5; + private readonly HttpClient _httpClient; + private readonly ILogger _logger; + + public Handler(AgentHttpClient agentHttpClient, ILogger logger) { - var listUrls = await _repo.GetAllAsync(); - throw new NotImplementedException(); + _httpClient = agentHttpClient.Client; + _logger = logger; + } + + public async Task> Handle(Command request, CancellationToken cancellationToken) + { + var validator = BuildValidator(cancellationToken); + var brokenUrls = new List(); + foreach (var url in request.Urls) + await validator.SendAsync(url, cancellationToken); + validator.Complete(); + while (await validator.OutputAvailableAsync(cancellationToken)) + { + var (url, result) = await validator.ReceiveAsync(cancellationToken); + if (!result) + brokenUrls.Add(url); + } + + await validator.Completion; + return brokenUrls; + } + + private TransformBlock BuildValidator(CancellationToken cancellationToken) + { + return new TransformBlock( + async u => + { + var errorMessage = $"The following URL is broken: {u}."; + try + { + var response = await _httpClient.GetAsync(u, cancellationToken); + if (response.IsSuccessStatusCode) + return (u, true); + _logger.LogError($"{errorMessage} {response.StatusCode}"); + return (u, false); + } + catch (HttpRequestException ex) + { + _logger.LogError(ex, errorMessage); + return (u, false); + } + catch (TaskCanceledException ex) + { + _logger.LogError(ex, errorMessage); + return (u, false); + } + }, + new ExecutionDataflowBlockOptions {MaxDegreeOfParallelism = MaxDegreeOfParallelism} + ); } } } diff --git a/src/FilterLists.Agent/Program.cs b/src/FilterLists.Agent/Program.cs index 5ae752efc..34f2daa20 100644 --- a/src/FilterLists.Agent/Program.cs +++ b/src/FilterLists.Agent/Program.cs @@ -17,7 +17,7 @@ public static async Task Main() BuildServiceProvider(); var mediator = _serviceProvider.GetService(); await mediator.Send(new CaptureLists.Command()); - await mediator.Send(new ValidateUrls.Command()); + await mediator.Send(new ValidateAllUrls.Command()); } private static void BuildServiceProvider()