| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980 |
- using Application.Abstractions.Cache;
- using Application.Abstractions.Data;
- using Application.Abstractions.Messaging;
- using Application.Abstractions.YouTube;
- using Microsoft.EntityFrameworkCore;
- using SharedKernel.Results;
- namespace Application.Features.Api.Channel.GetCreators;
- public sealed class Handler(
- IAppDbContext db,
- IYouTubeChannelCache channelCache,
- IYouTubeLiveStateStore liveStateStore,
- ICacheService cache
- ) : IQueryHandler<Query, Result<Response>>
- {
- private const string CacheKey = "channel:creators:main";
- private static readonly TimeSpan CacheTtl = TimeSpan.FromSeconds(30);
- public async Task<Result<Response>> Handle(Query request, CancellationToken ct)
- {
- var cached = await cache.GetAsync<List<CreatorItem>>(CacheKey, ct);
- if (cached is not null)
- {
- return new Response(cached);
- }
- var items = await BuildAsync(ct);
- await cache.SetAsync(CacheKey, items, CacheTtl, ct);
- return new Response(items);
- }
- private async Task<List<CreatorItem>> BuildAsync(CancellationToken ct)
- {
- // 활성 채널 + 회원 집계(팔로워)·등급 조인. 구독자/썸네일은 아래 YouTube 캐시에서 보강.
- var rows = await db.Channel.AsNoTracking().Where(c => c.IsActive).Select(c => new
- {
- c.SID,
- c.Name,
- c.Handle,
- FollowerCount = c.Member.MemberStats != null ? c.Member.MemberStats.FollowerCount : 0,
- GradeName = c.Member.MemberGrade != null ? c.Member.MemberGrade.KorName : null,
- GradeImage = c.Member.MemberGrade != null ? c.Member.MemberGrade.Image : null,
- GradeColor = c.Member.MemberGrade != null ? c.Member.MemberGrade.TextColor : null
- }).ToListAsync(ct);
- if (rows.Count == 0)
- {
- return [];
- }
- // 구독자 수·썸네일은 Redis YouTube 캐시에서 (엔티티 컬럼은 30일 미동기 시 0/null 로 비워짐)
- var ytCache = await channelCache.GetManyAsync(rows.Select(r => r.SID));
- var allLive = await liveStateStore.GetAllLiveAsync();
- var liveMap = allLive.Where(l => l.IsLive).ToDictionary(l => l.ChannelId);
- var items = new List<CreatorItem>(rows.Count);
- foreach (var r in rows)
- {
- var hasYt = ytCache.TryGetValue(r.SID, out var yt);
- items.Add(new CreatorItem(
- r.SID,
- r.Name,
- r.Handle,
- hasYt ? yt!.ThumbnailUrl : null,
- hasYt ? yt!.SubscriberCount : 0,
- r.FollowerCount,
- r.GradeName,
- r.GradeImage,
- r.GradeColor,
- liveMap.ContainsKey(r.SID)
- ));
- }
- return items;
- }
- }
|