Handler.cs 3.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. using Application.Abstractions.Data;
  2. using Application.Abstractions.Messaging;
  3. using Application.Abstractions.YouTube;
  4. using Microsoft.EntityFrameworkCore;
  5. using SharedKernel.Results;
  6. namespace Application.Features.Api.Studio.GetSettings;
  7. internal sealed class Handler(IAppDbContext db, IYouTubeChannelCache channelCache) : IQueryHandler<Query, Result<Response>>
  8. {
  9. private static readonly Response Empty = new(false, null, null, null, null, null, null, 0, 0, 0, null, null);
  10. public async Task<Result<Response>> Handle(Query request, CancellationToken ct)
  11. {
  12. var channel = await db.Channel.AsNoTracking().FirstOrDefaultAsync(c => c.MemberID == request.MemberID && c.IsActive, ct);
  13. if (channel is null)
  14. {
  15. return Result.Success(Empty);
  16. }
  17. // 채널 레코드가 존재하면 YouTube 연동된 상태
  18. // SID = YouTube 채널 ID (캐시 키로 사용)
  19. var ytChannelID = channel.YouTubeChannelID ?? channel.SID;
  20. var ytInfo = await channelCache.GetAsync(ytChannelID);
  21. if (ytInfo is not null)
  22. {
  23. // 캐시 데이터가 DB와 다르면 DB 동기화
  24. if (ytInfo.Title != channel.Name
  25. || ytInfo.SubscriberCount != channel.SubscriberCount
  26. || ytInfo.VideoCount != channel.VideoCount
  27. || ytInfo.ViewCount != channel.ViewCount
  28. || channel.YouTubeChannelID is null)
  29. {
  30. var tracked = await db.Channel.FindAsync([channel.ID], ct);
  31. if (tracked is not null)
  32. {
  33. tracked.UpdateYouTubeInfo(
  34. ytInfo.ChannelID, ytInfo.Title, ytInfo.CustomUrl,
  35. ytInfo.Description, ytInfo.ThumbnailUrl, ytInfo.BannerUrl,
  36. ytInfo.SubscriberCount, ytInfo.VideoCount, ytInfo.ViewCount,
  37. ytInfo.Email, ytInfo.PublishedAt);
  38. await db.SaveChangesAsync(ct);
  39. }
  40. }
  41. return Result.Success(new Response(
  42. true,
  43. ytInfo.Title,
  44. ytInfo.CustomUrl,
  45. ytInfo.Description,
  46. channel.YouTubeUrl,
  47. ytInfo.ThumbnailUrl,
  48. ytInfo.BannerUrl,
  49. ytInfo.SubscriberCount,
  50. ytInfo.VideoCount,
  51. ytInfo.ViewCount,
  52. ytInfo.PublishedAt,
  53. channel.DonationCode));
  54. }
  55. // 캐시 미스 → DB 데이터로 응답
  56. var isConnected = channel.YouTubeChannelID is not null;
  57. return Result.Success(new Response(
  58. isConnected,
  59. channel.Name,
  60. channel.Handle,
  61. channel.Description,
  62. channel.YouTubeUrl,
  63. channel.ThumbnailUrl,
  64. channel.BannerUrl,
  65. channel.SubscriberCount,
  66. channel.VideoCount,
  67. channel.ViewCount,
  68. channel.YouTubePublishedAt,
  69. channel.DonationCode));
  70. }
  71. }