Перепиливание под чистый DDD
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
using Knot.Shared.Kernel;
|
||||
using Knot.Shared.Kernel.Configuration;
|
||||
using Knot.Shared.Kernel.Constants;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Json;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediatR;
|
||||
|
||||
namespace Host.Application.Klipy.Queries;
|
||||
|
||||
public record GetTrendingGifsQuery : IQuery<JsonElement?>;
|
||||
|
||||
internal sealed class GetTrendingGifsQueryHandler : IQueryHandler<GetTrendingGifsQuery, JsonElement?>
|
||||
{
|
||||
private readonly ISettingsService _settings;
|
||||
private readonly IMemoryCache _cache;
|
||||
private readonly IHttpClientFactory _httpClientFactory;
|
||||
|
||||
public GetTrendingGifsQueryHandler(ISettingsService settings, IMemoryCache cache, IHttpClientFactory httpClientFactory)
|
||||
{
|
||||
_settings = settings;
|
||||
_cache = cache;
|
||||
_httpClientFactory = httpClientFactory;
|
||||
}
|
||||
|
||||
public async Task<Result<JsonElement?>> Handle(GetTrendingGifsQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var conf = _settings.Current;
|
||||
if (!conf.EnableKlipy || string.IsNullOrEmpty(conf.KlipyApiKey))
|
||||
return Result.Failure<JsonElement?>(new Error(Errors.KlipyNotConfigured, "Klipy is not configured"));
|
||||
|
||||
var cacheKeyTrending = $"klipy_trending_{conf.KlipyApiKey}";
|
||||
if (_cache.TryGetValue(cacheKeyTrending, out JsonElement cachedResult))
|
||||
return Result.Success<JsonElement?>(cachedResult);
|
||||
|
||||
var customerId = string.IsNullOrWhiteSpace(conf.KlipyCustomerId) ? Knot.Shared.Kernel.Constants.Klipy.DefaultCustomerId : conf.KlipyCustomerId;
|
||||
var client = _httpClientFactory.CreateClient();
|
||||
|
||||
var urlCo = string.Format(Knot.Shared.Kernel.Constants.Klipy.ApiUrlCo, conf.KlipyApiKey, Knot.Shared.Kernel.Constants.Klipy.ResourceTrending, "", customerId);
|
||||
|
||||
var response = await client.GetAsync(urlCo, cancellationToken);
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
if (response.StatusCode == System.Net.HttpStatusCode.NotFound)
|
||||
{
|
||||
var urlCom = string.Format(Knot.Shared.Kernel.Constants.Klipy.ApiUrlCom, conf.KlipyApiKey, Knot.Shared.Kernel.Constants.Klipy.ResourceTrending, "", customerId);
|
||||
response = await client.GetAsync(urlCom, cancellationToken);
|
||||
}
|
||||
|
||||
if (!response.IsSuccessStatusCode)
|
||||
return Result.Failure<JsonElement?>(new Error(Errors.KlipyApiError, "Klipy API Error"));
|
||||
}
|
||||
|
||||
var result = await response.Content.ReadFromJsonAsync<JsonElement>(cancellationToken: cancellationToken);
|
||||
_cache.Set(cacheKeyTrending, result, TimeSpan.FromMinutes(Knot.Shared.Kernel.Constants.Klipy.TrendingCacheMinutes));
|
||||
|
||||
return Result.Success<JsonElement?>(result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
using Knot.Shared.Kernel;
|
||||
using Knot.Shared.Kernel.Configuration;
|
||||
using Knot.Shared.Kernel.Constants;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Json;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediatR;
|
||||
|
||||
namespace Host.Application.Klipy.Queries;
|
||||
|
||||
public record SearchGifsQuery(string Query) : IQuery<JsonElement?>;
|
||||
|
||||
internal sealed class SearchGifsQueryHandler : IQueryHandler<SearchGifsQuery, JsonElement?>
|
||||
{
|
||||
private readonly ISettingsService _settings;
|
||||
private readonly IMemoryCache _cache;
|
||||
private readonly IHttpClientFactory _httpClientFactory;
|
||||
|
||||
public SearchGifsQueryHandler(ISettingsService settings, IMemoryCache cache, IHttpClientFactory httpClientFactory)
|
||||
{
|
||||
_settings = settings;
|
||||
_cache = cache;
|
||||
_httpClientFactory = httpClientFactory;
|
||||
}
|
||||
|
||||
public async Task<Result<JsonElement?>> Handle(SearchGifsQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var conf = _settings.Current;
|
||||
if (!conf.EnableKlipy || string.IsNullOrEmpty(conf.KlipyApiKey))
|
||||
return Result.Failure<JsonElement?>(new Error(Errors.KlipyNotConfigured, "Klipy is not configured"));
|
||||
|
||||
if (string.IsNullOrWhiteSpace(request.Query))
|
||||
return Result.Failure<JsonElement?>(new Error(Errors.InvalidQuery, "Invalid query parameter"));
|
||||
|
||||
var cacheKey = $"klipy_search_{conf.KlipyApiKey}_{request.Query.ToLowerInvariant()}";
|
||||
if (_cache.TryGetValue(cacheKey, out JsonElement cachedResult))
|
||||
return Result.Success<JsonElement?>(cachedResult);
|
||||
|
||||
var customerId = string.IsNullOrWhiteSpace(conf.KlipyCustomerId) ? Knot.Shared.Kernel.Constants.Klipy.DefaultCustomerId : conf.KlipyCustomerId;
|
||||
var client = _httpClientFactory.CreateClient();
|
||||
|
||||
var queryParam = $"q={Uri.EscapeDataString(request.Query)}";
|
||||
var urlCo = string.Format(Knot.Shared.Kernel.Constants.Klipy.ApiUrlCo, conf.KlipyApiKey, Knot.Shared.Kernel.Constants.Klipy.ResourceSearch, queryParam, customerId);
|
||||
|
||||
var response = await client.GetAsync(urlCo, cancellationToken);
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
if (response.StatusCode == System.Net.HttpStatusCode.NotFound)
|
||||
{
|
||||
var urlCom = string.Format(Knot.Shared.Kernel.Constants.Klipy.ApiUrlCom, conf.KlipyApiKey, Knot.Shared.Kernel.Constants.Klipy.ResourceSearch, queryParam, customerId);
|
||||
response = await client.GetAsync(urlCom, cancellationToken);
|
||||
}
|
||||
|
||||
if (!response.IsSuccessStatusCode)
|
||||
return Result.Failure<JsonElement?>(new Error(Errors.KlipySearchError, "Klipy Search API Error"));
|
||||
}
|
||||
|
||||
var result = await response.Content.ReadFromJsonAsync<JsonElement>(cancellationToken: cancellationToken);
|
||||
_cache.Set(cacheKey, result, TimeSpan.FromMinutes(Knot.Shared.Kernel.Constants.Klipy.SearchCacheMinutes));
|
||||
|
||||
return Result.Success<JsonElement?>(result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace Knot.Modules.Klipy;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
public static class DependencyInjection {
|
||||
public static IServiceCollection AddKlipyModule(this IServiceCollection services) {
|
||||
return services;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Shared\Knot.Shared.Kernel\Knot.Shared.Kernel.csproj" />
|
||||
<ProjectReference Include="..\..\Shared\Knot.Shared.Infrastructure\Knot.Shared.Infrastructure.csproj" />
|
||||
<ProjectReference Include="..\Conversations\Knot.Modules.Conversations.csproj" />
|
||||
<ProjectReference Include="..\Auth\Knot.Modules.Auth.csproj" />
|
||||
<ProjectReference Include="..\Stories\Knot.Modules.Stories.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Carter" Version="10.0.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,34 @@
|
||||
using Carter;
|
||||
using MediatR;
|
||||
using Knot.Shared.Kernel.Constants;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Host.Endpoints;
|
||||
|
||||
/// <summary>
|
||||
/// Регистрация эндпоинтов для сервиса Klipy.
|
||||
/// </summary>
|
||||
public sealed class KlipyEndpoints : ICarterModule
|
||||
{
|
||||
public void AddRoutes(IEndpointRouteBuilder app)
|
||||
{
|
||||
var group = app.MapGroup(Routes.ApiKlipy).RequireAuthorization();
|
||||
|
||||
group.MapGet("/trending", async (ISender sender, CancellationToken ct) =>
|
||||
{
|
||||
var result = await sender.Send(new Host.Application.Klipy.Queries.GetTrendingGifsQuery(), ct);
|
||||
return result.IsSuccess ? Results.Ok(result.Value) : Results.BadRequest(new { error = result.Error.Description });
|
||||
});
|
||||
|
||||
group.MapGet("/search", async ([FromQuery] string q, ISender sender, CancellationToken ct) =>
|
||||
{
|
||||
var result = await sender.Send(new Host.Application.Klipy.Queries.SearchGifsQuery(q), ct);
|
||||
return result.IsSuccess ? Results.Ok(result.Value) : Results.BadRequest(new { error = result.Error.Description });
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user