Skip to content

Commit

Permalink
#19 Queue-Consumer方式に変更
Browse files Browse the repository at this point in the history
  • Loading branch information
miyaji255 committed Mar 15, 2024
1 parent b8b9c37 commit e87454c
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 11 deletions.
14 changes: 11 additions & 3 deletions Epub/KoeBook.Epub/Contracts/Services/IScrapingClientService.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
namespace KoeBook.Epub.Contracts.Services;
using System.Net.Http.Headers;

namespace KoeBook.Epub.Contracts.Services;

public interface IScrapingClientService
{
/// <summary>
/// スクレイピングでGETする用
/// APIは不要
/// APIを叩く際は不要
/// </summary>
Task<string> GetAsStringAsync(string url, CancellationToken ct);

/// <summary>
/// スクレイピングでGETする用
/// APIを叩く際は不要
/// </summary>
ValueTask<HttpResponseMessage> GetAsync(string url, CancellationToken ct);
Task<ContentDispositionHeaderValue?> GetAsStreamAsync(string url, Stream destination, CancellationToken ct);
}
97 changes: 89 additions & 8 deletions Epub/KoeBook.Epub/Services/ScrapingClientService.cs
Original file line number Diff line number Diff line change
@@ -1,22 +1,103 @@
using KoeBook.Epub.Contracts.Services;
using System.Net.Http.Headers;
using KoeBook.Epub.Contracts.Services;

namespace KoeBook.Epub.Services;

public sealed class ScrapingClientService(IHttpClientFactory httpClientFactory, TimeProvider timeProvider) : IScrapingClientService, IDisposable
public sealed class ScrapingClientService : IScrapingClientService, IDisposable
{
private readonly IHttpClientFactory _httpClientFactory = httpClientFactory;
private readonly PeriodicTimer _periodicTimer = new(TimeSpan.FromSeconds(10), timeProvider);
private readonly IHttpClientFactory _httpClientFactory;
private readonly PeriodicTimer _periodicTimer;
private readonly Queue<Func<HttpClient, ValueTask>> _actionQueue = [];
private bool _workerActivated;

public ScrapingClientService(IHttpClientFactory httpClientFactory, TimeProvider timeProvider)
{
_httpClientFactory = httpClientFactory;
_periodicTimer = new(TimeSpan.FromSeconds(10), timeProvider);

Worker();
}

public void Dispose()
{
_periodicTimer.Dispose();
}

public async ValueTask<HttpResponseMessage> GetAsync(string url, CancellationToken ct)
private async void Worker()
{
lock (_actionQueue)
{
_workerActivated = true;
}

while (await _periodicTimer.WaitForNextTickAsync().ConfigureAwait(false) && _actionQueue.Count > 0)
{
if (_actionQueue.TryDequeue(out var action))
{
await action(_httpClientFactory.CreateClient()).ConfigureAwait(false);
}
}

lock (_actionQueue)
{
_workerActivated = false;
}
}

public Task<string> GetAsStringAsync(string url, CancellationToken ct)
{
await _periodicTimer.WaitForNextTickAsync(ct).ConfigureAwait(false);
var taskCompletion = new TaskCompletionSource<string>();
_actionQueue.Enqueue(async httpClient =>
{
if (ct.IsCancellationRequested)
taskCompletion.SetCanceled(ct);
try
{
var response = await httpClient.GetAsync(url, ct).ConfigureAwait(false);
taskCompletion.SetResult(await response.Content.ReadAsStringAsync(ct).ConfigureAwait(false));
}
catch (Exception ex)
{
taskCompletion.SetException(ex);
}
});

lock (_actionQueue)
{
if (!_workerActivated)
Worker();
}

return taskCompletion.Task;
}

public Task<ContentDispositionHeaderValue?> GetAsStreamAsync(string url, Stream destination, CancellationToken ct)
{
var taskCompletion = new TaskCompletionSource<ContentDispositionHeaderValue?>();
_actionQueue.Enqueue(async httpClient =>
{
if (ct.IsCancellationRequested)
taskCompletion.SetCanceled(ct);
try
{
var response = await httpClient.GetAsync(url, ct).ConfigureAwait(false);
await response.Content.CopyToAsync(destination, ct).ConfigureAwait(false);
taskCompletion.SetResult(response.Content.Headers.ContentDisposition);
}
catch (Exception ex)
{
taskCompletion.SetException(ex);
}
});

lock (_actionQueue)
{
if (!_workerActivated)
Worker();
}

var httpClient = _httpClientFactory.CreateClient();
return await httpClient.GetAsync(url, ct).ConfigureAwait(false);
return taskCompletion.Task;
}
}

0 comments on commit e87454c

Please sign in to comment.