Handler.cs 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758
  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.Channel.List;
  7. public sealed class Handler(IAppDbContext db, IYouTubeLiveStateStore liveStateStore, IYouTubeChannelCache channelCache) : IQueryHandler<Query, Result<Response>>
  8. {
  9. public async Task<Result<Response>> Handle(Query request, CancellationToken ct)
  10. {
  11. // 1. 활성 채널 목록 조회
  12. var channels = await db.Channel.AsNoTracking().Where(c => c.IsActive).Select(c => new { c.SID, c.Name, c.Handle }).ToListAsync(ct);
  13. if (channels.Count == 0)
  14. {
  15. return new Response([]);
  16. }
  17. // 2. YouTube 채널 정보 캐시 일괄 조회 (Redis — API 호출 0)
  18. var channelIds = channels.Select(c => c.SID).ToList();
  19. var ytCache = await channelCache.GetManyAsync(channelIds);
  20. // 3. 현재 라이브 중인 채널 상태 조회 (Redis — 0 unit)
  21. var allLive = await liveStateStore.GetAllLiveAsync();
  22. var liveMap = allLive.ToDictionary(l => l.ChannelId);
  23. // 4. 채널별 정보 조합
  24. var items = new List<ChannelItem>();
  25. foreach (var ch in channels)
  26. {
  27. var isLive = liveMap.TryGetValue(ch.SID, out var liveInfo);
  28. var hasYtInfo = ytCache.TryGetValue(ch.SID, out var ytInfo);
  29. items.Add(new ChannelItem(
  30. ch.SID,
  31. ch.Name,
  32. ch.Handle,
  33. hasYtInfo ? ytInfo!.ThumbnailUrl : null,
  34. hasYtInfo ? ytInfo!.SubscriberCount : 0,
  35. isLive,
  36. 0, // viewerCount — 추후 사이트 자체 접속자 수로 대체
  37. isLive ? liveInfo!.VideoId : null
  38. ));
  39. }
  40. // 5. 정렬: 온라인(시청자 많은 순) → 오프라인(이름순)
  41. items.Sort((a, b) => {
  42. if (a.IsLive && !b.IsLive) return -1;
  43. if (!a.IsLive && b.IsLive) return 1;
  44. if (a.IsLive && b.IsLive) return b.ViewerCount.CompareTo(a.ViewerCount);
  45. return string.Compare(a.Name, b.Name, StringComparison.OrdinalIgnoreCase);
  46. });
  47. return new Response(items);
  48. }
  49. }