| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273 |
- using Application.Abstractions.Data;
- using Microsoft.EntityFrameworkCore;
- using Microsoft.Extensions.DependencyInjection;
- using Microsoft.Extensions.Logging;
- namespace Infrastructure.YouTube;
- /// <summary>
- /// YouTube Data API v3 요청에 API Key를 자동으로 추가하는 DelegatingHandler
- /// DB Config에서 YouTube API Key를 조회하여 쿼리스트링에 &key=xxx 추가
- /// </summary>
- internal sealed class YouTubeApiKeyHandler(
- IServiceProvider serviceProvider,
- ILogger<YouTubeApiKeyHandler> logger
- ) : DelegatingHandler
- {
- private string? _cachedApiKey;
- private DateTime _cachedAt = DateTime.MinValue;
- private static readonly TimeSpan CacheDuration = TimeSpan.FromMinutes(30);
- protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
- {
- var apiKey = await GetApiKeyAsync(cancellationToken);
- if (!string.IsNullOrEmpty(apiKey) && request.RequestUri is not null)
- {
- // 이미 Authorization 헤더(OAuth)가 있으면 API Key 추가 안 함
- if (request.Headers.Authorization is null)
- {
- var uriStr = request.RequestUri.ToString();
- var separator = uriStr.Contains('?') ? "&" : "?";
- request.RequestUri = new Uri($"{uriStr}{separator}key={Uri.EscapeDataString(apiKey)}");
- }
- }
- else
- {
- logger.LogWarning("[YouTube] API Key가 비어있습니다. DB Config > External > YouTubeApiKeyEnc를 확인하세요.");
- }
- return await base.SendAsync(request, cancellationToken);
- }
- private async Task<string?> GetApiKeyAsync(CancellationToken ct)
- {
- if (_cachedApiKey is not null && DateTime.UtcNow - _cachedAt < CacheDuration)
- {
- return _cachedApiKey;
- }
- try
- {
- using var scope = serviceProvider.CreateScope();
- var db = scope.ServiceProvider.GetRequiredService<IAppDbContext>();
- var config = await db.Config.AsNoTracking().FirstOrDefaultAsync(ct);
- if (config is null)
- {
- return null;
- }
- // Config.External.YouTubeApiKeyEnc에서 API Key 가져옴
- _cachedApiKey = config.External?.YouTubeApiKeyEnc;
- _cachedAt = DateTime.UtcNow;
- return _cachedApiKey;
- }
- catch (Exception ex)
- {
- logger.LogWarning(ex, "[YouTube] API Key 조회 실패");
- return _cachedApiKey; // 이전 캐시 반환
- }
- }
- }
|