Handler.cs 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. using Application.Abstractions.Messaging;
  2. using Application.Abstractions.Data;
  3. using Application.Abstractions.Cache;
  4. using Application.Abstractions.Crypto;
  5. using Domain.Entities.Crypto;
  6. using Microsoft.EntityFrameworkCore;
  7. namespace Application.Features.Admin.Crypto.List.Sync;
  8. public sealed class Handler(IAppDbContext db, IUpbitClient upbit, ICacheService cache) : ICommandHandler<Command, Response>
  9. {
  10. public async Task<Response> Handle(Command request, CancellationToken ct)
  11. {
  12. var allMarkets = await upbit.GetMarketsAsync(ct);
  13. if (allMarkets.Count == 0)
  14. {
  15. throw new InvalidOperationException("Upbit API에서 마켓 데이터를 가져오지 못했습니다.");
  16. }
  17. var dbCoins = await db.Coin.Include(c => c.CoinMarket).ToListAsync(ct);
  18. var dbCoinMap = dbCoins.ToDictionary(c => c.Symbol, c => c, StringComparer.OrdinalIgnoreCase);
  19. var upbitSymbols = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
  20. int created = 0;
  21. int updated = 0;
  22. int delisted = 0;
  23. // 심볼별 첫 마켓에서 Coin 생성/갱신
  24. foreach (var market in allMarkets)
  25. {
  26. var symbol = market.Market.Split('-')[1];
  27. if (!upbitSymbols.Add(symbol))
  28. {
  29. continue;
  30. }
  31. if (dbCoinMap.TryGetValue(symbol, out var existing))
  32. {
  33. existing.SyncUpdate(market.KoreanName, market.EnglishName, market.MarketEvent.Warning);
  34. updated++;
  35. }
  36. else
  37. {
  38. var coin = Coin.SyncFromUpbit(symbol, market.KoreanName, market.EnglishName, market.MarketEvent.Warning);
  39. db.Coin.Add(coin);
  40. dbCoinMap[symbol] = coin;
  41. created++;
  42. }
  43. }
  44. // SaveChanges로 신규 코인 ID 확정
  45. await db.SaveChangesAsync(ct);
  46. // 거래쌍 동기화 (CoinMarket)
  47. foreach (var market in allMarkets)
  48. {
  49. var symbol = market.Market.Split('-')[1];
  50. if (!dbCoinMap.TryGetValue(symbol, out var coin))
  51. {
  52. continue;
  53. }
  54. if (!coin.CoinMarket.Any(m => m.Market.Equals(market.Market, StringComparison.OrdinalIgnoreCase)))
  55. {
  56. db.CoinMarket.Add(new CoinMarket { CoinID = coin.ID, Market = market.Market.ToUpper() });
  57. }
  58. }
  59. // 상폐 처리
  60. foreach (var coin in dbCoins)
  61. {
  62. if (!upbitSymbols.Contains(coin.Symbol) && !coin.IsDelisted)
  63. {
  64. coin.MarkDelisted();
  65. delisted++;
  66. }
  67. }
  68. await db.SaveChangesAsync(ct);
  69. await cache.RemoveByPrefixAsync("crypto:", ct);
  70. return new Response(created, updated, delisted);
  71. }
  72. }