From ea498d5a2a7ab74348a7b2579a4aec087bb8a892 Mon Sep 17 00:00:00 2001 From: felix-zhao <123852192+felix-zhaolei@users.noreply.github.com> Date: Sat, 14 Dec 2024 16:08:11 +0800 Subject: [PATCH 1/3] Entity handler sync (#1019) * modify: sync entity handler. --- .../Commons/AddressHelper.cs | 8 + .../Commons/ShiftChainHelper.cs | 31 +- .../Common/BusinessAlertProvider.cs | 66 +-- .../Options/BusinessAlertOptions.cs | 4 + .../Search/ISearchService.cs | 41 +- .../Transfer/ShiftChainService.cs | 27 +- .../CAAccountHandler.cs | 221 +-------- .../CAHolderHandler.cs | 426 +----------------- .../GuardianHandler.cs | 45 +- .../HolderStatisticHandler.cs | 121 +---- .../ReportHandler.cs | 37 +- .../SecondaryEmailHandler.cs | 99 +--- .../Service/CaAccountService.cs | 337 ++++++++++++++ .../Service/CaHolderService.cs | 422 +++++++++++++++++ .../Service/GuardianService.cs | 65 +++ .../Service/HolderStatisticService.cs | 139 ++++++ .../Service/ReportService.cs | 53 +++ .../Service/SecondaryEmailService.cs | 121 +++++ .../Service/TwitterStatisticService.cs | 76 ++++ .../Service/UserTokenService.cs | 67 +++ .../TwitterStatisticHandler.cs | 57 +-- .../UserBehaviorHandler.cs | 4 +- .../UserExtraInfoHandler.cs | 4 +- .../UserTokenEntityHandler.cs | 42 +- 24 files changed, 1407 insertions(+), 1106 deletions(-) create mode 100644 src/CAServer.EntityEventHandler.Core/Service/CaAccountService.cs create mode 100644 src/CAServer.EntityEventHandler.Core/Service/CaHolderService.cs create mode 100644 src/CAServer.EntityEventHandler.Core/Service/GuardianService.cs create mode 100644 src/CAServer.EntityEventHandler.Core/Service/HolderStatisticService.cs create mode 100644 src/CAServer.EntityEventHandler.Core/Service/ReportService.cs create mode 100644 src/CAServer.EntityEventHandler.Core/Service/SecondaryEmailService.cs create mode 100644 src/CAServer.EntityEventHandler.Core/Service/TwitterStatisticService.cs create mode 100644 src/CAServer.EntityEventHandler.Core/Service/UserTokenService.cs diff --git a/src/CAServer.Application.Contracts/Commons/AddressHelper.cs b/src/CAServer.Application.Contracts/Commons/AddressHelper.cs index 53cd6d31a..8c7ab6fec 100644 --- a/src/CAServer.Application.Contracts/Commons/AddressHelper.cs +++ b/src/CAServer.Application.Contracts/Commons/AddressHelper.cs @@ -77,4 +77,12 @@ public static string GetAelfChainId(string network) ? network : null; } + + public static bool IsFullAelfAddress(string address) + { + return address.StartsWith($"{CommonConstant.ELF}{CommonConstant.Underline}") && + (address.EndsWith($"{CommonConstant.Underline}{CommonConstant.MainChainId}") || + address.EndsWith($"{CommonConstant.Underline}{CommonConstant.TDVVChainId}") || + address.EndsWith($"{CommonConstant.Underline}{CommonConstant.TDVWChainId}")); + } } \ No newline at end of file diff --git a/src/CAServer.Application.Contracts/Commons/ShiftChainHelper.cs b/src/CAServer.Application.Contracts/Commons/ShiftChainHelper.cs index 7066cbd0e..b26fe0cdf 100644 --- a/src/CAServer.Application.Contracts/Commons/ShiftChainHelper.cs +++ b/src/CAServer.Application.Contracts/Commons/ShiftChainHelper.cs @@ -163,12 +163,17 @@ public static bool MatchForAddress(string chain, string fromChain, string addres public static AddressFormat GetAddressFormat(string fromChain, string address) { - if (address.Split("_").Length == 3 && address.Split("_")[1].Length == 50) + if (address.Contains(CommonConstant.Underline) && address.StartsWith(CommonConstant.ELF)) { + if (!IsAelfAddress(AddressHelper.ToShortAddress(address))) + { + return AddressFormat.NoSupport; + } if (address.EndsWith(CommonConstant.MainChainId)) { return AddressFormat.Main; - }else if (address.EndsWith(CommonConstant.TDVWChainId) || address.EndsWith(CommonConstant.TDVVChainId)) + } + if (address.EndsWith(CommonConstant.TDVWChainId) || address.EndsWith(CommonConstant.TDVVChainId)) { return AddressFormat.Dapp; } @@ -178,30 +183,25 @@ public static AddressFormat GetAddressFormat(string fromChain, string address) if (IsAelfAddress(address)) { - if (fromChain == CommonConstant.MainChainId) - { - return AddressFormat.Main; - } - - return AddressFormat.Dapp; + return fromChain == CommonConstant.MainChainId ? AddressFormat.Main : AddressFormat.Dapp; } - if (address.Length == 42) + if (IsEthAddress(address)) { return AddressFormat.ETH; } - if (address.Length == 34) + if (IsTrxAddress(address)) { return AddressFormat.TRX; } - if (address.Length == 43 || address.Length == 44) + if (IsSolanaAddress(address)) { return AddressFormat.Solana; } - if (address.Length == 48 && (address.StartsWith("EQ") || address.StartsWith("UQ"))) + if (IsTonAddress(address)) { return AddressFormat.TON; } @@ -227,6 +227,11 @@ private static bool IsAelfAddress(string address) return false; } } + + private static bool IsEthAddress(string address) => Regex.IsMatch(address, NetworkPatternMap["ETH"]); + private static bool IsTrxAddress(string address) => Regex.IsMatch(address, NetworkPatternMap["TRX"]); + private static bool IsSolanaAddress(string address) => Regex.IsMatch(address, NetworkPatternMap["Solana"]); + private static bool IsTonAddress(string address) => Regex.IsMatch(address, NetworkPatternMap["TON"]); public static bool VerifyAddress(string chain, string address) { @@ -242,6 +247,8 @@ public static bool VerifyAddress(string chain, string address) return !NetworkPatternMap.ContainsKey(chain) || Regex.IsMatch(address, NetworkPatternMap[chain]); } + + } public class ChainInfo diff --git a/src/CAServer.Application/Common/BusinessAlertProvider.cs b/src/CAServer.Application/Common/BusinessAlertProvider.cs index df3dbc5e2..f9a0a5eef 100644 --- a/src/CAServer.Application/Common/BusinessAlertProvider.cs +++ b/src/CAServer.Application/Common/BusinessAlertProvider.cs @@ -1,89 +1,55 @@ using System; using System.Threading.Tasks; using CAServer.Options; -using CAServer.Search; -using Microsoft.Extensions.Caching.Distributed; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; -using Newtonsoft.Json; -using Volo.Abp.Caching; using Volo.Abp.DependencyInjection; namespace CAServer.Common; public interface IBusinessAlertProvider { - public Task LoginRegisterFailureAlert(string sessionId, string dappName, string content); + public Task SendWebhookAsync(string sessionId, string title, string errorMsg, string content); } public class BusinessAlertProvider : IBusinessAlertProvider, ISingletonDependency { - private readonly IDistributedCache _distributedCache; private readonly IHttpClientService _httpClientService; private readonly ILogger _logger; private readonly BusinessAlertOptions _businessAlertOptions; - - + public BusinessAlertProvider( - IDistributedCache distributedCache, IHttpClientService httpClientService, ILogger logger, IOptionsSnapshot businessAlertOptions) { - _distributedCache = distributedCache; _httpClientService = httpClientService; _logger = logger; _businessAlertOptions = businessAlertOptions.Value; } - - private int loginRegisterTimeoutSeconds = 60; - private int loginRegisterNumber = 10; - - public async Task LoginRegisterFailureAlert(string sessionId, string dappName, string content) + + private long _lastSendTime = DateTimeOffset.Now.ToUnixTimeSeconds(); + public async Task SendWebhookAsync(string sessionId, string title, string errorMsg, string content) { try { - string key = $"{sessionId};{dappName ?? "default"}"; - string value = await _distributedCache.GetAsync(key) ?? "0"; - value = (int.Parse(value) + 1).ToString(); - await _distributedCache.SetAsync(key, value, new DistributedCacheEntryOptions { AbsoluteExpiration = DateTimeOffset.Now.AddSeconds(loginRegisterTimeoutSeconds) }); - - int number = int.Parse(value); - if (number < loginRegisterNumber) + if (DateTimeOffset.Now.ToUnixTimeSeconds() - _lastSendTime < _businessAlertOptions.SendInterval) { - return false; + return; } - await _distributedCache.RemoveAsync(key); - await SendWebhook(sessionId, content, dappName); - - return true; + var msg = new + { + msg_type = "text", + content = new + { text = $" title : {title}\n sessionId : {sessionId} \n errorMsg : {errorMsg} \n content : {content}" } + }; + await _httpClientService.PostAsync(_businessAlertOptions.Webhook, msg); + _lastSendTime = DateTimeOffset.Now.ToUnixTimeSeconds(); } catch (Exception e) { - _logger.LogError(e, "LoginRegisterFailureAlert error, sessionId = {0}, content = {1}", sessionId, content); + _logger.LogError(e, "SendWebhookAsync error, sessionId = {0}, content = {1}", sessionId, content); } - - return false; - } - - private long sendIntervalSeconds = 10; - private long lastSendTime = DateTimeOffset.Now.ToUnixTimeSeconds(); - private string title = "Login or registration failed."; - private async Task SendWebhook(string sessionId, string content, string dappName) - { - if (DateTimeOffset.Now.ToUnixTimeSeconds() - lastSendTime < sendIntervalSeconds) - { - return; - } - - var msg = new - { - msg_type = "text", - content = new - { text = $" title : {title}\n sessionId : {sessionId} \n dappName : {dappName} \n content : {content}" } - }; - await _httpClientService.PostAsync(_businessAlertOptions.Webhook, msg); - lastSendTime = DateTimeOffset.Now.ToUnixTimeSeconds(); } } \ No newline at end of file diff --git a/src/CAServer.Application/Options/BusinessAlertOptions.cs b/src/CAServer.Application/Options/BusinessAlertOptions.cs index c50111ad5..e439dc606 100644 --- a/src/CAServer.Application/Options/BusinessAlertOptions.cs +++ b/src/CAServer.Application/Options/BusinessAlertOptions.cs @@ -3,4 +3,8 @@ namespace CAServer.Options; public class BusinessAlertOptions { public string Webhook { get; set; } + /// + /// seconds + /// + public int SendInterval { get; set; } = 3; } \ No newline at end of file diff --git a/src/CAServer.Application/Search/ISearchService.cs b/src/CAServer.Application/Search/ISearchService.cs index ab0016541..2eb8ba287 100644 --- a/src/CAServer.Application/Search/ISearchService.cs +++ b/src/CAServer.Application/Search/ISearchService.cs @@ -225,33 +225,12 @@ public override async Task GetListByLucenceAsync(string indexName, GetLi public class AccountRecoverySearchService : SearchService { private readonly IndexSettingOptions _indexSettingOptions; - private readonly IBusinessAlertProvider _businessAlertProvider; public override string IndexName => $"{_indexSettingOptions.IndexPrefix.ToLower()}.accountrecoverindex"; - public AccountRecoverySearchService(INESTRepository nestRepository, IBusinessAlertProvider businessAlertProvider, + public AccountRecoverySearchService(INESTRepository nestRepository, IOptionsSnapshot indexSettingOptions) : base(nestRepository) { _indexSettingOptions = indexSettingOptions.Value; - _businessAlertProvider = businessAlertProvider; - } - - - public async override Task GetListByLucenceAsync(string indexName, GetListInput input) - { - string result = await base.GetListByLucenceAsync(indexName, input); - var indexList = JsonConvert.DeserializeObject>(result); - if (indexList.TotalCount > 0) - { - foreach (var index in indexList.Items) - { - if (index.RecoverySuccess != true) - { - _businessAlertProvider.LoginRegisterFailureAlert(input.Filter,input.DappName, JsonConvert.SerializeObject(index)); - } - } - } - - return result; } } @@ -267,24 +246,6 @@ public AccountRegisterSearchService(INESTRepository _indexSettingOptions = indexSettingOptions.Value; _businessAlertProvider = businessAlertProvider; } - - public async override Task GetListByLucenceAsync(string indexName, GetListInput input) - { - string result = await base.GetListByLucenceAsync(indexName, input); - var indexList = JsonConvert.DeserializeObject>(result); - if (indexList.TotalCount > 0) - { - foreach (var index in indexList.Items) - { - if (index.RegisterSuccess != true) - { - _businessAlertProvider.LoginRegisterFailureAlert(input.Filter, input.DappName,JsonConvert.SerializeObject(index)); - } - } - } - - return result; - } } public class OrderSearchService : SearchService { diff --git a/src/CAServer.Application/Transfer/ShiftChainService.cs b/src/CAServer.Application/Transfer/ShiftChainService.cs index f235654f0..cef909af2 100644 --- a/src/CAServer.Application/Transfer/ShiftChainService.cs +++ b/src/CAServer.Application/Transfer/ShiftChainService.cs @@ -111,6 +111,15 @@ public async Task> GetSendNetworkList(GetSendNet }; } + if (request.ToAddress.Contains(CommonConstant.Underline) && request.ToAddress.StartsWith(CommonConstant.ELF)) + { + return new ResponseWrapDto + { + Code = ETransferConstant.SuccessCode, + Data = result + }; + } + if (addressFormat is AddressFormat.Main or AddressFormat.Dapp) { result.NetworkList.Add(_networkCacheService.GetNetwork(request.ChainId)); @@ -128,7 +137,7 @@ public async Task> GetSendNetworkList(GetSendNet Message = ETransferConstant.InvalidAddressMessage }; } - + return new ResponseWrapDto { Code = ETransferConstant.SuccessCode, @@ -212,10 +221,12 @@ private async Task setSendByETransfer(SendNetworkDto result, GetSendNetworkListR } - private async Task setReceiveByETransfer(Dictionary receiveNetworkMap, Dictionary networkMap) + private async Task setReceiveByETransfer(Dictionary receiveNetworkMap, + Dictionary networkMap) { string type = "Deposit"; - var optionList = await _transferAppService.GetTokenOptionListAsync(new GetTokenOptionListRequestDto { Type = type }); + var optionList = + await _transferAppService.GetTokenOptionListAsync(new GetTokenOptionListRequestDto { Type = type }); foreach (var token in optionList.Data.TokenList) { var toToken = token.ToTokenList.FirstOrDefault(p => p.Symbol.Equals(token.Symbol)); @@ -228,7 +239,8 @@ private async Task setReceiveByETransfer(Dictionary r ReceiveNetworkDto receiveNetwork = initAELFChain(symbol); receiveNetworkMap[symbol] = receiveNetwork; var price = await _tokenAppService.GetTokenPriceListAsync(new List { symbol }); - _logger.LogInformation("setReceiveByETransfer symbol = {0} price = {1}", symbol, JsonConvert.SerializeObject(price)); + _logger.LogInformation("setReceiveByETransfer symbol = {0} price = {1}", symbol, + JsonConvert.SerializeObject(price)); var maxAmount = ShiftChainHelper.GetMaxAmount(price.Items[0].PriceInUsd); foreach (var chainId in toToken.ChainIdList) { @@ -318,7 +330,8 @@ private async Task setReceiveByEBridge(Dictionary sendEBridgeMap, Dictionary networkMap, + private void setSendByEBridge(Dictionary sendEBridgeMap, + Dictionary networkMap, EBridgeLimiterDto limiters) { foreach (var limiter in limiters.Items) @@ -397,7 +410,9 @@ public Task GetSupportNetworkListAsync() continue; supportedNetworkList.Add(new NetworkBasicInfo() { - Network = item.Network == CommonConstant.BaseNetwork ? CommonConstant.BaseNetworkName : item.Network, + Network = item.Network == CommonConstant.BaseNetwork + ? CommonConstant.BaseNetworkName + : item.Network, Name = AddressHelper.GetNetworkName(item.Network) }); } diff --git a/src/CAServer.EntityEventHandler.Core/CAAccountHandler.cs b/src/CAServer.EntityEventHandler.Core/CAAccountHandler.cs index fbacf03c6..29305573e 100644 --- a/src/CAServer.EntityEventHandler.Core/CAAccountHandler.cs +++ b/src/CAServer.EntityEventHandler.Core/CAAccountHandler.cs @@ -2,25 +2,12 @@ using System.Threading.Tasks; using AElf.Indexing.Elasticsearch; using CAServer.Account; -using CAServer.CAAccount.Dtos; -using CAServer.Commons; using CAServer.ContractEventHandler; -using CAServer.CryptoGift; -using CAServer.Dtos; using CAServer.Entities.Es; +using CAServer.EntityEventHandler.Core.Service; using CAServer.Etos; -using CAServer.Grains; -using CAServer.Grains.Grain.Account; -using CAServer.Grains.Grain.Device; -using CAServer.Growth; -using CAServer.Hubs; -using CAServer.Monitor; -using CAServer.Monitor.Logger; -using Microsoft.Extensions.Caching.Distributed; using Microsoft.Extensions.Logging; using Newtonsoft.Json; -using Orleans; -using Volo.Abp.Caching; using Volo.Abp.DependencyInjection; using Volo.Abp.EventBus.Distributed; using Volo.Abp.ObjectMapping; @@ -35,82 +22,48 @@ public class CaAccountHandler : IDistributedEventHandler, ITransientDependency { - private readonly INESTRepository _registerRepository; - private readonly INESTRepository _recoverRepository; + private readonly ICaAccountService _caAccountService; private readonly INESTRepository _accelerateRegisterRepository; private readonly INESTRepository _accelerateRecoverRepository; private readonly IObjectMapper _objectMapper; private readonly ILogger _logger; - private readonly IClusterClient _clusterClient; - private readonly IDistributedEventBus _distributedEventBus; - private readonly IIndicatorLogger _indicatorLogger; - private readonly IGrowthAppService _growthAppService; - private readonly ICryptoGiftAppService _cryptoGiftAppService; - private readonly IDistributedCache _distributedCache; - public CaAccountHandler(INESTRepository registerRepository, - INESTRepository recoverRepository, + public CaAccountHandler( IObjectMapper objectMapper, ILogger logger, - IDistributedEventBus distributedEventBus, - IClusterClient clusterClient, - IIndicatorLogger indicatorLogger, IGrowthAppService growthAppService, INESTRepository accelerateRegisterRepository, INESTRepository accelerateRecoverRepository, - ICryptoGiftAppService cryptoGiftAppService, - IDistributedCache distributedCache) + ICaAccountService caAccountService) { - _registerRepository = registerRepository; - _recoverRepository = recoverRepository; _objectMapper = objectMapper; _logger = logger; - _clusterClient = clusterClient; - _distributedEventBus = distributedEventBus; - _indicatorLogger = indicatorLogger; - _growthAppService = growthAppService; _accelerateRegisterRepository = accelerateRegisterRepository; _accelerateRecoverRepository = accelerateRecoverRepository; - _cryptoGiftAppService = cryptoGiftAppService; - _distributedCache = distributedCache; + _caAccountService = caAccountService; } public async Task HandleEventAsync(AccountRegisterCreateEto eventData) { try { - _logger.LogInformation("received account register message:{0}", JsonConvert.SerializeObject(eventData)); - _logger.LogDebug("the first event: create register"); - var register = _objectMapper.Map(eventData); - if (eventData.GuardianInfo.ZkLoginInfo != null) - { - register.GuardianInfo.ZkLoginInfo = eventData.GuardianInfo.ZkLoginInfo; - } - register.RegisterStatus = AccountOperationStatus.Pending; - await _registerRepository.AddAsync(register); - _logger.LogDebug($"register add success: {JsonConvert.SerializeObject(register)}"); + _ = _caAccountService.HandleAccountRegisterCreateAsync(eventData); } catch (Exception ex) { - _logger.LogError(ex, "{Message}", JsonConvert.SerializeObject(eventData)); + _logger.LogError(ex, "handle AccountRegisterCreateEto error, {data}", JsonConvert.SerializeObject(eventData)); } } + public async Task HandleEventAsync(AccountRecoverCreateEto eventData) { try { - _logger.LogInformation("received account recover message:{0}", JsonConvert.SerializeObject(eventData)); - _logger.LogDebug("the first event: create recover"); - - var recover = _objectMapper.Map(eventData); - - recover.RecoveryStatus = AccountOperationStatus.Pending; - await _recoverRepository.AddAsync(recover); - _logger.LogDebug($"recovery add success: {JsonConvert.SerializeObject(recover)}"); + _ = _caAccountService.HandleAccountRecoverCreateAsync(eventData); } catch (Exception ex) { - _logger.LogError(ex, "{Message}", JsonConvert.SerializeObject(eventData)); + _logger.LogError(ex, "handle AccountRecoverCreateEto error, {data}", JsonConvert.SerializeObject(eventData)); } } @@ -118,179 +71,33 @@ public async Task HandleEventAsync(CreateHolderEto eventData) { try { - _logger.LogInformation("CreateHolderEto CryptoGiftTransferToRedPackage eventData:{0}", JsonConvert.SerializeObject(eventData)); - if (eventData.RegisterSuccess != null && eventData.RegisterSuccess.Value) - { - await _distributedCache.SetAsync(string.Format(CryptoGiftConstant.RegisterCachePrefix, eventData.CaHash), JsonConvert.SerializeObject(new CryptoGiftReferralDto - { - CaHash = eventData.CaHash, - CaAddress = eventData.CaAddress, - ReferralInfo = eventData.ReferralInfo, - IsNewUser = true, - IpAddress = eventData.IpAddress - }), new DistributedCacheEntryOptions() - { - AbsoluteExpiration = DateTimeOffset.UtcNow.AddDays(1) - }); - } - - _logger.LogDebug("the second event: update register grain."); - - await SwapGrainStateAsync(eventData.CaHash, eventData.GrainId); - - var grain = _clusterClient.GetGrain(eventData.GrainId); - var result = - await grain.UpdateRegisterResultAsync( - _objectMapper.Map(eventData)); - - if (!result.Success) - { - _logger.LogError("update register grain fail, message:{message}", result.Message); - throw new Exception(result.Message); - } - - _logger.LogDebug("the third event: update register in es"); - var register = _objectMapper.Map(result.Data); - - register.RegisterStatus = GetAccountStatus(eventData.RegisterSuccess); - await _registerRepository.UpdateAsync(register); - - await PublicRegisterMessageAsync(result.Data, eventData.Context); - - var duration = DateTime.UtcNow - register.CreateTime; - _indicatorLogger.LogInformation(MonitorTag.Register, MonitorTag.Register.ToString(), - (int)(duration?.TotalMilliseconds ?? 0)); - - _logger.LogInformation("register update success: id: {id}, status: {status}", register.Id.ToString(), - register.RegisterStatus); - - await AddGrowthInfoAsync(eventData.CaHash, eventData.ReferralInfo); + _ = _caAccountService.HandleCreateHolderAsync(eventData); } catch (Exception ex) { - _logger.LogError(ex, "update register info error, data: {data}", JsonConvert.SerializeObject(eventData)); + _logger.LogError(ex, "handle CreateHolderEto error, {data}", JsonConvert.SerializeObject(eventData)); } } - private async Task PublicRegisterMessageAsync(RegisterGrainDto register, HubRequestContext Context) - { - await _distributedEventBus.PublishAsync(new AccountRegisterCompletedEto - { - RegisterCompletedMessage = new RegisterCompletedMessageDto - { - RegisterStatus = GetAccountStatus(register.RegisterSuccess), - CaAddress = register.CaAddress, - CaHash = register.CaHash, - RegisterMessage = register.RegisterMessage - }, - Context = Context - }); - - await _distributedEventBus.PublishAsync(new HolderExtraInfoCompletedEto - { - Status = GetAccountStatus(register.RegisterSuccess), - CaAddress = register.CaAddress, - CaHash = register.CaHash, - GrainId = register.GrainId - }); - } public async Task HandleEventAsync(SocialRecoveryEto eventData) { try { - _logger.LogInformation("SocialRecoveryEto CryptoGiftTransferToRedPackage eventData:{0}", JsonConvert.SerializeObject(eventData)); - if (eventData.RecoverySuccess != null && eventData.RecoverySuccess.Value) - { - await _distributedCache.SetAsync(string.Format(CryptoGiftConstant.SocialRecoveryCachePrefix, eventData.CaHash), JsonConvert.SerializeObject(new CryptoGiftReferralDto - { - CaHash = eventData.CaHash, - CaAddress = eventData.CaAddress, - ReferralInfo = eventData.ReferralInfo, - IsNewUser = false, - IpAddress = eventData.IpAddress - }), new DistributedCacheEntryOptions() - { - AbsoluteExpiration = DateTimeOffset.UtcNow.AddDays(1) - }); - await _distributedCache.RemoveAsync(string.Format(CryptoGiftConstant.RegisterCachePrefix, eventData.CaHash)); - var cachedResult = await _distributedCache.GetAsync(string.Format(CryptoGiftConstant.SocialRecoveryCachePrefix, eventData.CaHash)); - _logger.LogInformation("SocialRecoveryEto CryptoGiftTransferToRedPackage cachedResult:{cachedResult}", cachedResult); - } - _logger.LogDebug("the second event: update recover grain."); - - var grain = _clusterClient.GetGrain(eventData.GrainId); - var updateResult = await grain.UpdateRecoveryResultAsync( - _objectMapper.Map(eventData)); - - if (!updateResult.Success) - { - _logger.LogError("{Message}", updateResult.Message); - } - - _logger.LogDebug("the third event: update register in es"); - var recover = _objectMapper.Map(updateResult.Data); - recover.RecoveryStatus = GetAccountStatus(eventData.RecoverySuccess); - await _recoverRepository.UpdateAsync(recover); - - await PublicRecoverMessageAsync(updateResult.Data, eventData.Context); - - var duration = DateTime.UtcNow - recover.CreateTime; - _indicatorLogger.LogInformation(MonitorTag.SocialRecover, MonitorTag.SocialRecover.ToString(), - (int)(duration?.TotalMilliseconds ?? 0)); - - _logger.LogDebug("register update success: id: {id}, status: {status}", recover.Id.ToString(), - recover.RecoveryStatus); + _ = _caAccountService.HandleSocialRecoveryAsync(eventData); } catch (Exception ex) { - _logger.LogError(ex, "{Message}", JsonConvert.SerializeObject(eventData)); + _logger.LogError(ex, "handle SocialRecoveryEto error, {data}", JsonConvert.SerializeObject(eventData)); } } - private async Task PublicRecoverMessageAsync(RecoveryGrainDto recover, HubRequestContext context) - { - await _distributedEventBus.PublishAsync(new AccountRecoverCompletedEto - { - RecoveryCompletedMessage = new RecoveryCompletedMessageDto - { - RecoveryStatus = GetAccountStatus(recover.RecoverySuccess), - RecoveryMessage = recover.RecoveryMessage, - CaHash = recover.CaHash, - CaAddress = recover.CaAddress - }, - Context = context - }); - } - private string GetAccountStatus(bool? accountSuccess) => !accountSuccess.HasValue ? AccountOperationStatus.Pending : accountSuccess.Value ? AccountOperationStatus.Pass : AccountOperationStatus.Fail; - private async Task SwapGrainStateAsync(string caHash, string grainId) - { - var newDeviceGrain = _clusterClient.GetGrain(GrainIdHelper.GenerateGrainId("Device", caHash)); - var prevDeviceGrain = _clusterClient.GetGrain(GrainIdHelper.GenerateGrainId("Device", grainId)); - var salt = await prevDeviceGrain.GetOrGenerateSaltAsync(); - await newDeviceGrain.SetSaltAsync(salt); - } - - private async Task AddGrowthInfoAsync(string caHash, ReferralInfo referralInfo) - { - if (referralInfo == null || referralInfo.ReferralCode.IsNullOrEmpty()) - { - _logger.LogInformation("no need to add growth info, caHash:{caHash}", caHash); - return; - } - - await _growthAppService.CreateGrowthInfoAsync(caHash, referralInfo); - _logger.LogInformation( - "create growth info success, caHash:{caHash}, referralCode:{referralCode}, projectCode:{projectCode}", - caHash, referralInfo.ReferralCode, referralInfo.ProjectCode ?? string.Empty); - } - public async Task HandleEventAsync(AccelerateCreateHolderEto eventData) { var accelerateRegisterIndex = _objectMapper.Map(eventData); diff --git a/src/CAServer.EntityEventHandler.Core/CAHolderHandler.cs b/src/CAServer.EntityEventHandler.Core/CAHolderHandler.cs index f58bd5593..cbbb0e22c 100644 --- a/src/CAServer.EntityEventHandler.Core/CAHolderHandler.cs +++ b/src/CAServer.EntityEventHandler.Core/CAHolderHandler.cs @@ -1,32 +1,8 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text.RegularExpressions; using System.Threading.Tasks; -using AElf.Indexing.Elasticsearch; -using CAServer.CAAccount.Provider; -using CAServer.Contacts; -using CAServer.Contacts.Provider; -using CAServer.Entities.Es; +using CAServer.EntityEventHandler.Core.Service; using CAServer.Etos; -using CAServer.Grains.Grain.Contacts; -using CAServer.Guardian; -using CAServer.Guardian.Provider; -using CAServer.Options; -using CAServer.Tokens; -using CAServer.Tokens.Dtos; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using Nest; -using Newtonsoft.Json; -using Orleans; using Volo.Abp.DependencyInjection; using Volo.Abp.EventBus.Distributed; -using GuardianInfoBase = CAServer.Guardian.GuardianInfoBase; -using GuardianType = CAServer.Account.GuardianType; -using ImInfo = CAServer.Entities.Es.ImInfo; -using IObjectMapper = Volo.Abp.ObjectMapping.IObjectMapper; - namespace CAServer.EntityEventHandler.Core; public class CAHolderHandler : IDistributedEventHandler, @@ -34,413 +10,25 @@ public class CAHolderHandler : IDistributedEventHandler, IDistributedEventHandler , ITransientDependency { - private readonly INESTRepository _caHolderRepository; - private readonly IObjectMapper _objectMapper; - private readonly ILogger _logger; - private readonly IClusterClient _clusterClient; - private readonly IUserTokenAppService _userTokenAppService; - private readonly IContactProvider _contactProvider; - private readonly INESTRepository _contactRepository; - private readonly IGuardianProvider _guardianProvider; - private readonly INESTRepository _userExtraInfoRepository; - private readonly INESTRepository _guardianRepository; - private readonly IGuardianAppService _guardianAppService; - private readonly IUserProfilePictureProvider _userProfilePictureProvider; - private readonly Random _random; - private readonly ChatBotOptions _chatBotOptions; - private readonly IContactAppService _contactAppService; + private readonly ICaHolderService _caHolderService; - public CAHolderHandler(INESTRepository caHolderRepository, - IObjectMapper objectMapper, - ILogger logger, - IClusterClient clusterClient, - IUserTokenAppService userTokenAppService, - IContactProvider contactProvider, - INESTRepository contactRepository, - IGuardianProvider guardianProvider, - INESTRepository userExtraInfoRepository, - INESTRepository guardianRepository, - IGuardianAppService guardianAppService, - IUserProfilePictureProvider userProfilePictureProvider, IOptionsSnapshot chatBotOptions, - IContactAppService contactAppService) + public CAHolderHandler(ICaHolderService caHolderService) { - _caHolderRepository = caHolderRepository; - _objectMapper = objectMapper; - _logger = logger; - _clusterClient = clusterClient; - _userTokenAppService = userTokenAppService; - _contactProvider = contactProvider; - _contactRepository = contactRepository; - _guardianProvider = guardianProvider; - _userExtraInfoRepository = userExtraInfoRepository; - _guardianRepository = guardianRepository; - _guardianAppService = guardianAppService; - _userProfilePictureProvider = userProfilePictureProvider; - _contactAppService = contactAppService; - _chatBotOptions = chatBotOptions.Value; - _random = new Random(); + _caHolderService = caHolderService; } public async Task HandleEventAsync(CreateUserEto eventData) { - string changedNickname = string.Empty; - string identifierHash = string.Empty; - string nickname = eventData.UserId.ToString("N").Substring(0, 8); - try - { - var loginGuardianInfoBase = await GetLoginAccountInfo(eventData.CaHash); - if (loginGuardianInfoBase == null) - { - var (name, hash) = await GenerateNewAccountFormatForThirdParty(nickname, eventData); - changedNickname = name; - identifierHash = hash; - } - else - { - changedNickname = await GenerateNewAccountFormat(nickname, loginGuardianInfoBase); - identifierHash = loginGuardianInfoBase.IdentifierHash; - } - } - catch (Exception e) - { - _logger.LogError(e, "GenerateNewAccountFormat error, userId={0}, caHash={1}", eventData.UserId, - eventData.CaHash); - } - - try - { - var grain = _clusterClient.GetGrain(eventData.UserId); - var caHolderGrainDto = _objectMapper.Map(eventData); - var pictures = _userProfilePictureProvider.GetDefaultUserPictures(); - string picture; - if (!pictures.IsNullOrEmpty()) - { - picture = pictures[_random.Next(pictures.Count)]; - } - else - { - picture = string.Empty; - } - - if (changedNickname.IsNullOrEmpty() || nickname.Equals(changedNickname)) - { - caHolderGrainDto.Nickname = nickname; - caHolderGrainDto.PopedUp = false; - caHolderGrainDto.ModifiedNickname = false; - caHolderGrainDto.Avatar = picture; - } - else - { - caHolderGrainDto.Nickname = changedNickname; - caHolderGrainDto.PopedUp = true; - caHolderGrainDto.ModifiedNickname = true; - caHolderGrainDto.IdentifierHash = identifierHash; - caHolderGrainDto.Avatar = picture; - } - - var result = await grain.AddHolderWithAvatarAsync(caHolderGrainDto); - if (!result.Success) - { - _logger.LogError("create holder fail: {message}, userId: {userId}, aAHash: {caHash}", result.Message, - eventData.UserId, eventData.CaHash); - return; - } - - var index = _objectMapper.Map(result.Data); - await _caHolderRepository.AddAsync(index); - - //Add Bot Contact - var botContact = new ContactIndex() - { - Id = Guid.NewGuid(), - UserId = eventData.UserId, - Name = "", - Index = "K", - Avatar = _chatBotOptions.Avatar, - ImInfo = new ImInfo - { - RelationId = _chatBotOptions.RelationId, - PortkeyId = _chatBotOptions.PortkeyId, - Name = _chatBotOptions.Name, - }, - IsDeleted = false, - IsImputation = false, - CreateTime = DateTime.UtcNow, - ModificationTime = DateTime.UtcNow, - ContactType = 1 - }; - await _contactRepository.AddOrUpdateAsync(botContact); - _logger.LogDebug("new register account add chatBot.register is {register},ChatBot is {chatBot}", - JsonConvert.SerializeObject(eventData), JsonConvert.SerializeObject(botContact)); - await _userTokenAppService.AddUserTokenAsync(eventData.UserId, new AddUserTokenInput()); - } - catch (Exception ex) - { - _logger.LogError(ex, "{Message}: {Data}", "Create CA holder fail", JsonConvert.SerializeObject(eventData)); - } - } - - private async Task GetLoginAccountInfo(string caHash) - { - //if the guardian type is third party, the holderInfo is null - var holderInfo = await _guardianProvider.GetGuardiansAsync(null, caHash); - var guardianInfo = holderInfo.CaHolderInfo.FirstOrDefault(g => g.GuardianList != null - && g.GuardianList.Guardians.Count > 0); - if (guardianInfo == null) - { - return null; - } - - GuardianInfoBase guardianInfoBase = guardianInfo?.GuardianList.Guardians.FirstOrDefault(g => g.IsLoginGuardian); - if (guardianInfoBase == null || !guardianInfoBase.Type.Equals(((int)GuardianType.GUARDIAN_TYPE_OF_EMAIL) + "")) - { - return null; - } - - var list = new List(); - list.Add(guardianInfoBase.IdentifierHash); - var hashDic = await GetIdentifiersAsync(list); - guardianInfoBase.GuardianIdentifier = hashDic[guardianInfoBase.IdentifierHash]; - return guardianInfoBase; - } - - private async Task> GetIdentifiersAsync(List identifierHashList) - { - var mustQuery = new List, QueryContainer>> - { - q => q.Terms(i => i.Field(f => f.IdentifierHash).Terms(identifierHashList)) - }; - - QueryContainer Filter(QueryContainerDescriptor f) => - f.Bool(b => b.Must(mustQuery)); - - var guardians = await _guardianRepository.GetListAsync(Filter); - - var result = guardians.Item2.Where(t => t.IsDeleted == false); - - return result.ToDictionary(t => t.IdentifierHash, t => t.Identifier); - } - - private async Task GenerateNewAccountFormat(string nickname, GuardianInfoBase guardianInfoBase) - { - if (guardianInfoBase == null) - { - return nickname; - } - - if (!guardianInfoBase.IsLoginGuardian) - { - return nickname; - } - - string guardianIdentifier = guardianInfoBase.GuardianIdentifier; - string guardianType = guardianInfoBase.Type; - if (guardianIdentifier == null) - { - return nickname; - } - - //email according to GuardianType - try - { - if ((int)GuardianType.GUARDIAN_TYPE_OF_EMAIL == int.Parse(guardianType)) - { - if (!guardianIdentifier.Contains("@")) - { - return nickname; - } - - return GetEmailFormat(nickname, guardianIdentifier, string.Empty, string.Empty); - } - } - catch (Exception e) - { - _logger.LogError(e, "GenerateNewAccountFormat error"); - } - - return nickname; - } - - private async Task> GenerateNewAccountFormatForThirdParty(string nickname, - CreateUserEto eventData) - { - if (eventData.ChainId.IsNullOrEmpty() || eventData.CaHash.IsNullOrEmpty()) - { - return new Tuple(nickname, string.Empty); - } - - GuardianResultDto guardianResultDto = null; - try - { - GuardianIdentifierDto guardianIdentifierDto = new GuardianIdentifierDto(); - guardianIdentifierDto.ChainId = eventData.ChainId; - guardianIdentifierDto.CaHash = eventData.CaHash; - guardianResultDto = await _guardianAppService.GetGuardianIdentifiersAsync(guardianIdentifierDto); - } - catch (Exception e) - { - _logger.LogError(e, "call GetGuardianIdentifiersAsync error, ChainId={1},CaHash={2}", eventData.ChainId, - eventData.CaHash); - } - - if (guardianResultDto == null) - { - return new Tuple(nickname, string.Empty); - } - - var guardian = guardianResultDto.GuardianList.Guardians.FirstOrDefault(g => g.IsLoginGuardian); - if (guardian == null) - { - return new Tuple(nickname, string.Empty); - } - - string address = string.Empty; - if (!guardianResultDto.CaAddress.IsNullOrEmpty()) - { - address = guardianResultDto.CaAddress; - } - - if ("Telegram".Equals(guardian.Type) || "Twitter".Equals(guardian.Type) || "Facebook".Equals(guardian.Type)) - { - return new Tuple(GetFirstNameFormat(nickname, guardian.FirstName, address), - guardian.IdentifierHash); - } - - if ("Email".Equals(guardian.Type) && !guardian.GuardianIdentifier.IsNullOrEmpty()) - { - return new Tuple( - GetEmailFormat(nickname, guardian.GuardianIdentifier, guardian.FirstName, address), - guardian.IdentifierHash); - } - - return new Tuple( - GetEmailFormat(nickname, guardian.ThirdPartyEmail, guardian.FirstName, address), guardian.IdentifierHash); - } - - private async Task> GetUserExtraInfoAsync(List identifiers) - { - try - { - if (identifiers == null || identifiers.Count == 0) - { - return new List(); - } - - var mustQuery = new List, QueryContainer>> - { - q => q.Terms(i => i.Field(f => f.Id).Terms(identifiers)) - }; - - QueryContainer Filter(QueryContainerDescriptor f) => - f.Bool(b => b.Must(mustQuery)); - - var userExtraInfos = await _userExtraInfoRepository.GetListAsync(Filter); - - return userExtraInfos.Item2; - } - catch (Exception ex) - { - _logger.LogError(ex, "in GetUserExtraInfoAsync"); - } - - return new List(); - } - - private string GetEmailFormat(string nickname, string guardianIdentifier, string firstName, string address) - { - if (guardianIdentifier.IsNullOrEmpty()) - { - return GetFirstNameFormat(nickname, firstName, address); - } - - int index = guardianIdentifier.LastIndexOf("@"); - if (index < 0) - { - return nickname; - } - - string frontPart = guardianIdentifier.Substring(0, index); - string backPart = guardianIdentifier.Substring(index); - int frontLength = frontPart.Length; - if (frontLength > 4) - { - return frontPart.Substring(0, 4) + "***" + backPart; - } - else - { - return frontPart + "***" + backPart; - } - } - - private string GetFirstNameFormat(string nickname, string firstName, string address) - { - if (firstName.IsNullOrEmpty() && address.IsNullOrEmpty()) - { - return nickname; - } - - if (!firstName.IsNullOrEmpty() && Regex.IsMatch(firstName, "^\\w+$")) - { - return firstName + "***"; - } - - if (!address.IsNullOrEmpty()) - { - int length = address.Length; - return address.Substring(0, 3) + "***" + address.Substring(length - 3); - } - - return nickname; + _ = _caHolderService.CreateUserAsync(eventData); } public async Task HandleEventAsync(UpdateCAHolderEto eventData) { - try - { - await _caHolderRepository.UpdateAsync(_objectMapper.Map(eventData)); - _logger.LogInformation("caHolder wallet name update success, id: {id}", eventData.Id); - - var contacts = await _contactProvider.GetAddedContactsAsync(eventData.UserId); - if (contacts == null || contacts.Count == 0) return; - - foreach (var contact in contacts) - { - if (contact.CaHolderInfo == null) return; - var grain = _clusterClient.GetGrain(contact.Id); - var updateResult = await grain.UpdateContactInfo(eventData.Nickname, eventData.Avatar); - - if (!updateResult.Success) - { - _logger.LogWarning("contact wallet name update fail, contactId: {id}, message:{message}", - contact.Id, updateResult.Message); - break; - } - - contact.CaHolderInfo.WalletName = eventData.Nickname; - contact.Avatar = eventData.Avatar; - contact.ModificationTime = DateTime.UtcNow; - contact.Index = updateResult.Data.Index; - - await _contactRepository.UpdateAsync(contact); - _logger.LogInformation("contact wallet name update success, contactId: {id}", contact.Id); - } - } - catch (Exception ex) - { - _logger.LogError(ex, "update nick name error, id:{id}, nickName:{nickName}, userId:{userId}", - eventData.Id.ToString(), eventData.Nickname, eventData.UserId.ToString()); - } + _ = _caHolderService.UpdateCaHolderAsync(eventData); } public async Task HandleEventAsync(DeleteCAHolderEto eventData) { - try - { - await _caHolderRepository.UpdateAsync(_objectMapper.Map(eventData)); - } - catch (Exception ex) - { - _logger.LogError(ex, "Delete holder error, userId: {userId}", eventData.UserId.ToString()); - } + _ = _caHolderService.DeleteCaHolderAsync(eventData); } } \ No newline at end of file diff --git a/src/CAServer.EntityEventHandler.Core/GuardianHandler.cs b/src/CAServer.EntityEventHandler.Core/GuardianHandler.cs index 4f3427963..b87d2d0a8 100644 --- a/src/CAServer.EntityEventHandler.Core/GuardianHandler.cs +++ b/src/CAServer.EntityEventHandler.Core/GuardianHandler.cs @@ -1,61 +1,28 @@ -using System; using System.Threading.Tasks; -using AElf.Indexing.Elasticsearch; -using CAServer.Entities.Es; +using CAServer.EntityEventHandler.Core.Service; using CAServer.Guardian; -using Microsoft.Extensions.Logging; -using Newtonsoft.Json; using Volo.Abp.DependencyInjection; using Volo.Abp.EventBus.Distributed; -using Volo.Abp.ObjectMapping; namespace CAServer.EntityEventHandler.Core; public class GuardianHandler : IDistributedEventHandler, IDistributedEventHandler, ITransientDependency { - private readonly INESTRepository _guardianRepository; - private readonly IObjectMapper _objectMapper; - private readonly ILogger _logger; + private readonly IGuardianService _guardianService; - public GuardianHandler( - INESTRepository guardianRepository, - IObjectMapper objectMapper, - ILogger logger) + public GuardianHandler(IGuardianService guardianService) { - _guardianRepository = guardianRepository; - _objectMapper = objectMapper; - _logger = logger; + _guardianService = guardianService; } public async Task HandleEventAsync(GuardianEto eventData) { - try - { - var guardian = _objectMapper.Map(eventData); - await _guardianRepository.AddOrUpdateAsync(guardian); - - _logger.LogDebug("Guardian add or update success, id: {id}", eventData.Id); - } - catch (Exception ex) - { - _logger.LogError(ex, "{Message}: {Data}", "Guardian add fail", - JsonConvert.SerializeObject(eventData)); - } + _ = _guardianService.AddGuardianAsync(eventData); } public async Task HandleEventAsync(GuardianDeleteEto eventData) { - try - { - var guardian = _objectMapper.Map(eventData); - await _guardianRepository.UpdateAsync(guardian); - - _logger.LogDebug("Guardian delete success, id: {id}", eventData.Id); - } - catch (Exception ex) - { - _logger.LogError(ex, "Guardian delete fail, id: {id}", eventData.Id); - } + _ = _guardianService.DeleteGuardianAsync(eventData); } } \ No newline at end of file diff --git a/src/CAServer.EntityEventHandler.Core/HolderStatisticHandler.cs b/src/CAServer.EntityEventHandler.Core/HolderStatisticHandler.cs index 56f2c9171..34ea7f846 100644 --- a/src/CAServer.EntityEventHandler.Core/HolderStatisticHandler.cs +++ b/src/CAServer.EntityEventHandler.Core/HolderStatisticHandler.cs @@ -1,137 +1,28 @@ -using System; -using System.Collections.Generic; -using System.Text.RegularExpressions; using System.Threading.Tasks; -using AElf.Indexing.Elasticsearch; -using CAServer.Account; -using CAServer.Entities.Es; +using CAServer.EntityEventHandler.Core.Service; using CAServer.Etos; -using CAServer.IpInfo; -using Microsoft.Extensions.Logging; -using Newtonsoft.Json; using Volo.Abp.DependencyInjection; using Volo.Abp.EventBus.Distributed; -using Volo.Abp.ObjectMapping; -using JsonSerializer = System.Text.Json.JsonSerializer; namespace CAServer.EntityEventHandler.Core; public class HolderStatisticHandler : IDistributedEventHandler, IDistributedEventHandler, ITransientDependency { - private readonly INESTRepository _holderStatisticRepository; - private readonly ILogger _logger; - private readonly IIpInfoClient _infoClient; - private readonly IObjectMapper _objectMapper; + private readonly IHolderStatisticService _holderStatisticService; - private const string IpPattern = - @"^([0,1]?\d{1,2}|2([0-4][0-9]|5[0-5]))(\.([0,1]?\d{1,2}|2([0-4][0-9]|5[0-5]))){3}$"; - - private const string IpKey = "ip"; - private const string ActivityIdKey = "activityId"; - private const string IpAddressKey = "ipAddress"; - - public HolderStatisticHandler(INESTRepository holderStatisticRepository, - ILogger logger, IIpInfoClient infoClient, IObjectMapper objectMapper) + public HolderStatisticHandler(IHolderStatisticService holderStatisticService) { - _holderStatisticRepository = holderStatisticRepository; - _logger = logger; - _infoClient = infoClient; - _objectMapper = objectMapper; + _holderStatisticService = holderStatisticService; } public async Task HandleEventAsync(HolderExtraInfoEto eventData) { - try - { - if (eventData.ExtraInfo.IsNullOrEmpty()) return; - - var statisticIndex = new HolderStatisticIndex - { - Id = eventData.GrainId, - OperationType = eventData.OperationType.ToString(), - CreateTime = DateTime.UtcNow, - Status = AccountOperationStatus.Pending.ToString() - }; - - if (eventData.ExtraInfo.TryGetValue(ActivityIdKey, out var activityId)) - { - statisticIndex.ActivityId = activityId.ToString(); - } - - if (eventData.ExtraInfo.TryGetValue(IpAddressKey, out var ipAddress)) - { - statisticIndex.IpAddress = ipAddress.ToString(); - } - - if (eventData.ExtraInfo.TryGetValue(IpKey, out var ip)) - { - statisticIndex.IpAddress = ip.ToString(); - } - - if (!statisticIndex.IpAddress.IsNullOrEmpty()) - { - statisticIndex.CountryInfo = await GetCountryInfoAsync(statisticIndex.IpAddress); - } - - await _holderStatisticRepository.AddOrUpdateAsync(statisticIndex); - _logger.LogInformation( - "save HolderExtraInfo success, grainId:{grainId},ip:{ip},country:{country},activityId:{activityId}", - statisticIndex.Id, statisticIndex.IpAddress ?? "-", statisticIndex.CountryInfo?.CountryName ?? "-", - statisticIndex.ActivityId ?? "-"); - } - catch (Exception e) - { - _logger.LogError( - e, "save HolderExtraInfo data = {0} error {1}", JsonSerializer.Serialize(eventData), e.ToString()); - } + _ = _holderStatisticService.HandleHolderExtraInfoAsync(eventData); } public async Task HandleEventAsync(HolderExtraInfoCompletedEto eventData) { - try - { - var statisticIndex = await _holderStatisticRepository.GetAsync(eventData.GrainId); - if (statisticIndex == null) return; - - statisticIndex.CaAddress = eventData.CaAddress; - statisticIndex.CaHash = eventData.CaHash; - statisticIndex.Status = eventData.Status; - - await _holderStatisticRepository.AddOrUpdateAsync(statisticIndex); - _logger.LogInformation( - "save completed HolderExtraInfo success, grainId:{grainId},ip:{ip},country:{country},activityId:{activityId}", - statisticIndex.Id, statisticIndex.IpAddress ?? "-", statisticIndex.CountryInfo?.CountryName ?? "-", - statisticIndex.ActivityId ?? "-"); - } - catch (Exception e) - { - _logger.LogError( - e, "save completed HolderExtraInfo data = {0} error {1}", JsonSerializer.Serialize(eventData), - e.ToString()); - } - } - - private async Task GetCountryInfoAsync(string ip) - { - if (!(new Regex(IpPattern).IsMatch(ip))) - { - return null; - } - - var countryInfo = await _infoClient.GetCountryInfoAsync(ip); - if (countryInfo == null) - { - return null; - } - - if (countryInfo.Error != null) - { - _logger.LogError("get ip info error, ip:{0}, error info:{1}", ip, - JsonConvert.SerializeObject(countryInfo.Error)); - return null; - } - - return _objectMapper.Map(countryInfo); + _ = _holderStatisticService.HandleHolderExtraInfoCompletedAsync(eventData); } } \ No newline at end of file diff --git a/src/CAServer.EntityEventHandler.Core/ReportHandler.cs b/src/CAServer.EntityEventHandler.Core/ReportHandler.cs index abf68364d..e1ce63187 100644 --- a/src/CAServer.EntityEventHandler.Core/ReportHandler.cs +++ b/src/CAServer.EntityEventHandler.Core/ReportHandler.cs @@ -1,49 +1,22 @@ -using System; using System.Threading.Tasks; -using AElf.Indexing.Elasticsearch; using CAServer.DataReporting.Etos; -using CAServer.Entities.Es; -using Microsoft.Extensions.Logging; -using Newtonsoft.Json; +using CAServer.EntityEventHandler.Core.Service; using Volo.Abp.DependencyInjection; using Volo.Abp.EventBus.Distributed; -using Volo.Abp.ObjectMapping; namespace CAServer.EntityEventHandler.Core; public class ReportHandler : IDistributedEventHandler, ITransientDependency { - private readonly INESTRepository _repository; - private readonly IObjectMapper _objectMapper; - private readonly ILogger _logger; + private readonly IReportService _reportService; - public ReportHandler(INESTRepository repository, IObjectMapper objectMapper, - ILogger logger) + public ReportHandler(IReportService reportService) { - _repository = repository; - _objectMapper = objectMapper; - _logger = logger; + _reportService = reportService; } public async Task HandleEventAsync(AccountReportEto eventData) { - try - { - var index = _objectMapper.Map(eventData); - var reportIndex = await _repository.GetAsync(index.Id); - if (reportIndex == null) - { - index.CreateTime = DateTime.UtcNow; - } - - await _repository.AddOrUpdateAsync(index); - _logger.LogInformation("[AccountReport] account report info handle success, caHash:{caHash}", - eventData.CaHash); - } - catch (Exception e) - { - _logger.LogError(e, "[AccountReport] handle report account data error, data:{data}", - JsonConvert.SerializeObject(eventData)); - } + _ = _reportService.HandleAccountReportAsync(eventData); } } \ No newline at end of file diff --git a/src/CAServer.EntityEventHandler.Core/SecondaryEmailHandler.cs b/src/CAServer.EntityEventHandler.Core/SecondaryEmailHandler.cs index 7644fae0b..0a9068671 100644 --- a/src/CAServer.EntityEventHandler.Core/SecondaryEmailHandler.cs +++ b/src/CAServer.EntityEventHandler.Core/SecondaryEmailHandler.cs @@ -1,109 +1,22 @@ -using System; -using System.Linq; using System.Threading.Tasks; -using AElf.Indexing.Elasticsearch; -using CAServer.CAAccount.Provider; -using CAServer.Common; -using CAServer.Entities.Es; +using CAServer.EntityEventHandler.Core.Service; using CAServer.Etos; -using CAServer.Guardian.Provider; -using GraphQL; -using Microsoft.Extensions.Logging; -using Microsoft.IdentityModel.Tokens; -using Newtonsoft.Json; using Volo.Abp.DependencyInjection; using Volo.Abp.EventBus.Distributed; -using Volo.Abp.ObjectMapping; namespace CAServer.EntityEventHandler.Core; public class SecondaryEmailHandler : IDistributedEventHandler, ITransientDependency { - private readonly INESTRepository _guardianRepository; - private readonly IObjectMapper _objectMapper; - private readonly ILogger _logger; - private readonly IGraphQLHelper _graphQlHelper; - private readonly ICAAccountProvider _accountProvider; + private readonly ISecondaryEmailService _secondaryEmailService; - public SecondaryEmailHandler(INESTRepository guardianRepository, - IObjectMapper objectMapper, - ILogger logger, - IGraphQLHelper graphQlHelper, - ICAAccountProvider accountProvider) + public SecondaryEmailHandler(ISecondaryEmailService secondaryEmailService) { - _guardianRepository = guardianRepository; - _objectMapper = objectMapper; - _logger = logger; - _graphQlHelper = graphQlHelper; - _accountProvider = accountProvider; + _secondaryEmailService = secondaryEmailService; } - + public async Task HandleEventAsync(AccountEmailEto eventData) { - if (string.IsNullOrEmpty(eventData.SecondaryEmail) || string.IsNullOrEmpty(eventData.CaHash)) - { - _logger.LogError("SecondaryEmailHandler Params Error received AccountEmailEto:{0}", JsonConvert.SerializeObject(eventData)); - return; - } - //1. consumer get guardianList by caHash through GraphQl - var guardiansDto = await GetCaHolderInfoAsync(eventData.CaHash); - if (guardiansDto == null || guardiansDto.CaHolderInfo.IsNullOrEmpty()) - { - _logger.LogError("SecondaryEmailHandler query guardians from graphql failed guardiansDto:{0}", JsonConvert.SerializeObject(eventData)); - return; - } - var guardians = guardiansDto.CaHolderInfo - .Where(dto => dto.GuardianList != null) - .Select(dto => dto.GuardianList).ToList(); - foreach (var guardian in guardians.SelectMany(guardianBaseList => guardianBaseList.Guardians)) - { - if (guardian == null) - { - continue; - } - GuardianIndex guardianIndex = null; - try - { - //2. extract guardian's IdentifierHash, query - guardianIndex = await _accountProvider.GetIdentifiersAsync(guardian.IdentifierHash); - } - catch (Exception e) - { - _logger.LogError(e, "HandleEventAsync get guardianFromGraphQL failed identifierHash:{0}", guardian.IdentifierHash); - } - if (guardianIndex == null) - { - continue; - } - //3、append Guardian's(from es) caHash and secondaryEmail fields - guardianIndex.CaHash = eventData.CaHash; - guardianIndex.SecondaryEmail = eventData.SecondaryEmail; - try - { - await _guardianRepository.AddOrUpdateAsync(guardianIndex); - } - catch (Exception e) - { - _logger.LogError(e, "HandleEventAsync AddOrUpdateAsync failed identifierHash:{0} caHash:{1} email:{2}", - guardian.IdentifierHash, eventData.CaHash, eventData.SecondaryEmail); - } - } - } - - private async Task GetCaHolderInfoAsync(string caHash, int skipCount = 0, - int maxResultCount = 10) - { - return await _graphQlHelper.QueryAsync(new GraphQLRequest - { - Query = @" - query($caHash:String,$skipCount:Int!,$maxResultCount:Int!) { - caHolderInfo(dto: {caHash:$caHash,skipCount:$skipCount,maxResultCount:$maxResultCount}){ - id,chainId,caHash,caAddress,originChainId,managerInfos{address,extraData},guardianList{guardians{verifierId,identifierHash,salt,isLoginGuardian,type}}} - }", - Variables = new - { - caHash, skipCount, maxResultCount - } - }); + _ = _secondaryEmailService.HandleAccountEmailAsync(eventData); } } \ No newline at end of file diff --git a/src/CAServer.EntityEventHandler.Core/Service/CaAccountService.cs b/src/CAServer.EntityEventHandler.Core/Service/CaAccountService.cs new file mode 100644 index 000000000..13333afa1 --- /dev/null +++ b/src/CAServer.EntityEventHandler.Core/Service/CaAccountService.cs @@ -0,0 +1,337 @@ +using System; +using System.Threading.Tasks; +using AElf.Indexing.Elasticsearch; +using CAServer.Account; +using CAServer.CAAccount.Dtos; +using CAServer.Common; +using CAServer.Commons; +using CAServer.ContractEventHandler; +using CAServer.CryptoGift; +using CAServer.Dtos; +using CAServer.Entities.Es; +using CAServer.Etos; +using CAServer.Grains; +using CAServer.Grains.Grain.Account; +using CAServer.Grains.Grain.Device; +using CAServer.Growth; +using CAServer.Hubs; +using CAServer.Monitor; +using CAServer.Monitor.Logger; +using Microsoft.Extensions.Caching.Distributed; +using Microsoft.Extensions.Logging; +using Newtonsoft.Json; +using Org.BouncyCastle.Ocsp; +using Orleans; +using Volo.Abp.Caching; +using Volo.Abp.DependencyInjection; +using Volo.Abp.EventBus.Distributed; +using Volo.Abp.ObjectMapping; + +namespace CAServer.EntityEventHandler.Core.Service; + +public interface ICaAccountService +{ + Task HandleAccountRegisterCreateAsync(AccountRegisterCreateEto eventData); + Task HandleAccountRecoverCreateAsync(AccountRecoverCreateEto eventData); + Task HandleCreateHolderAsync(CreateHolderEto eventData); + Task HandleSocialRecoveryAsync(SocialRecoveryEto eventData); +} + +public class CaAccountService : ICaAccountService, ISingletonDependency +{ + private readonly INESTRepository _registerRepository; + private readonly INESTRepository _recoverRepository; + private readonly INESTRepository _accelerateRegisterRepository; + private readonly INESTRepository _accelerateRecoverRepository; + private readonly IObjectMapper _objectMapper; + private readonly ILogger _logger; + private readonly IClusterClient _clusterClient; + private readonly IDistributedEventBus _distributedEventBus; + private readonly IIndicatorLogger _indicatorLogger; + private readonly IGrowthAppService _growthAppService; + private readonly ICryptoGiftAppService _cryptoGiftAppService; + private readonly IDistributedCache _distributedCache; + private readonly IBusinessAlertProvider _businessAlertProvider; + + public CaAccountService(INESTRepository registerRepository, + INESTRepository recoverRepository, + IObjectMapper objectMapper, + ILogger logger, + IDistributedEventBus distributedEventBus, + IClusterClient clusterClient, + IIndicatorLogger indicatorLogger, IGrowthAppService growthAppService, + INESTRepository accelerateRegisterRepository, + INESTRepository accelerateRecoverRepository, + ICryptoGiftAppService cryptoGiftAppService, + IDistributedCache distributedCache, IBusinessAlertProvider businessAlertProvider) + { + _registerRepository = registerRepository; + _recoverRepository = recoverRepository; + _objectMapper = objectMapper; + _logger = logger; + _clusterClient = clusterClient; + _distributedEventBus = distributedEventBus; + _indicatorLogger = indicatorLogger; + _growthAppService = growthAppService; + _accelerateRegisterRepository = accelerateRegisterRepository; + _accelerateRecoverRepository = accelerateRecoverRepository; + _cryptoGiftAppService = cryptoGiftAppService; + _distributedCache = distributedCache; + _businessAlertProvider = businessAlertProvider; + } + + public async Task HandleAccountRegisterCreateAsync(AccountRegisterCreateEto eventData) + { + try + { + _logger.LogInformation("received account register message:{0}", JsonConvert.SerializeObject(eventData)); + _logger.LogInformation("the first event: create register"); + var register = _objectMapper.Map(eventData); + if (eventData.GuardianInfo.ZkLoginInfo != null) + { + register.GuardianInfo.ZkLoginInfo = eventData.GuardianInfo.ZkLoginInfo; + } + + register.RegisterStatus = AccountOperationStatus.Pending; + await _registerRepository.AddAsync(register); + _logger.LogInformation("register add success: {data}", JsonConvert.SerializeObject(register)); + } + catch (Exception e) + { + _logger.LogError(e, "[HandleMessageError] type:{type}, data:{data}, errMsg:{errMsg}", + eventData.GetType().Name, JsonConvert.SerializeObject(eventData), e.StackTrace ?? "-"); + } + } + + public async Task HandleAccountRecoverCreateAsync(AccountRecoverCreateEto eventData) + { + try + { + _logger.LogInformation("received account recover message:{0}", JsonConvert.SerializeObject(eventData)); + _logger.LogInformation("the first event: create recover"); + + var recover = _objectMapper.Map(eventData); + + recover.RecoveryStatus = AccountOperationStatus.Pending; + await _recoverRepository.AddAsync(recover); + _logger.LogInformation("recovery add success: {data}", JsonConvert.SerializeObject(recover)); + } + catch (Exception e) + { + _logger.LogError(e, "[HandleMessageError] type:{type}, data:{data}, errMsg:{errMsg}", + eventData.GetType().Name, JsonConvert.SerializeObject(eventData), e.StackTrace ?? "-"); + } + } + + public async Task HandleCreateHolderAsync(CreateHolderEto eventData) + { + try + { + _logger.LogInformation("CreateHolderEto CryptoGiftTransferToRedPackage eventData:{0}", + JsonConvert.SerializeObject(eventData)); + if (eventData.RegisterSuccess != null && eventData.RegisterSuccess.Value) + { + await _distributedCache.SetAsync( + string.Format(CryptoGiftConstant.RegisterCachePrefix, eventData.CaHash), + JsonConvert.SerializeObject(new CryptoGiftReferralDto + { + CaHash = eventData.CaHash, + CaAddress = eventData.CaAddress, + ReferralInfo = eventData.ReferralInfo, + IsNewUser = true, + IpAddress = eventData.IpAddress + }), new DistributedCacheEntryOptions() + { + AbsoluteExpiration = DateTimeOffset.UtcNow.AddDays(1) + }); + } + + _logger.LogDebug("the second event: update register grain."); + + await SwapGrainStateAsync(eventData.CaHash, eventData.GrainId); + + var grain = _clusterClient.GetGrain(eventData.GrainId); + var result = + await grain.UpdateRegisterResultAsync( + _objectMapper.Map(eventData)); + + if (!result.Success) + { + _logger.LogError("update register grain fail, message:{message}", result.Message); + throw new Exception(result.Message); + } + + _logger.LogDebug("the third event: update register in es"); + var register = _objectMapper.Map(result.Data); + + register.RegisterStatus = GetAccountStatus(eventData.RegisterSuccess); + await _registerRepository.UpdateAsync(register); + + await RegisterAlertAsync(register); + await PublicRegisterMessageAsync(result.Data, eventData.Context); + + var duration = DateTime.UtcNow - register.CreateTime; + _indicatorLogger.LogInformation(MonitorTag.Register, MonitorTag.Register.ToString(), + (int)(duration?.TotalMilliseconds ?? 0)); + + _logger.LogInformation("register update success: id: {id}, status: {status}", register.Id.ToString(), + register.RegisterStatus); + + await AddGrowthInfoAsync(eventData.CaHash, eventData.ReferralInfo); + } + catch (Exception e) + { + _logger.LogError(e, "[HandleMessageError] type:{type}, data:{data}, errMsg:{errMsg}", + eventData.GetType().Name, JsonConvert.SerializeObject(eventData), e.StackTrace ?? "-"); + } + } + + public async Task HandleSocialRecoveryAsync(SocialRecoveryEto eventData) + { + try + { + _logger.LogInformation("SocialRecoveryEto CryptoGiftTransferToRedPackage eventData:{0}", + JsonConvert.SerializeObject(eventData)); + if (eventData.RecoverySuccess != null && eventData.RecoverySuccess.Value) + { + await _distributedCache.SetAsync( + string.Format(CryptoGiftConstant.SocialRecoveryCachePrefix, eventData.CaHash), + JsonConvert.SerializeObject(new CryptoGiftReferralDto + { + CaHash = eventData.CaHash, + CaAddress = eventData.CaAddress, + ReferralInfo = eventData.ReferralInfo, + IsNewUser = false, + IpAddress = eventData.IpAddress + }), new DistributedCacheEntryOptions() + { + AbsoluteExpiration = DateTimeOffset.UtcNow.AddDays(1) + }); + await _distributedCache.RemoveAsync(string.Format(CryptoGiftConstant.RegisterCachePrefix, + eventData.CaHash)); + var cachedResult = + await _distributedCache.GetAsync(string.Format(CryptoGiftConstant.SocialRecoveryCachePrefix, + eventData.CaHash)); + _logger.LogInformation("SocialRecoveryEto CryptoGiftTransferToRedPackage cachedResult:{cachedResult}", + cachedResult); + } + + _logger.LogDebug("the second event: update recover grain."); + + var grain = _clusterClient.GetGrain(eventData.GrainId); + var updateResult = await grain.UpdateRecoveryResultAsync( + _objectMapper.Map(eventData)); + + if (!updateResult.Success) + { + _logger.LogError("update recovery grain fail, {message}", updateResult.Message); + } + + _logger.LogDebug("the third event: update recover in es"); + var recover = _objectMapper.Map(updateResult.Data); + recover.RecoveryStatus = GetAccountStatus(eventData.RecoverySuccess); + await _recoverRepository.UpdateAsync(recover); + + await RecoverAlertAsync(recover); + await PublicRecoverMessageAsync(updateResult.Data, eventData.Context); + + var duration = DateTime.UtcNow - recover.CreateTime; + _indicatorLogger.LogInformation(MonitorTag.SocialRecover, MonitorTag.SocialRecover.ToString(), + (int)(duration?.TotalMilliseconds ?? 0)); + + _logger.LogDebug("recover update success: id: {id}, status: {status}", recover.Id.ToString(), + recover.RecoveryStatus); + } + catch (Exception e) + { + _logger.LogError(e, "[HandleMessageError] type:{type}, data:{data}, errMsg:{errMsg}", + eventData.GetType().Name, JsonConvert.SerializeObject(eventData), e.StackTrace ?? "-"); + } + } + + private async Task PublicRecoverMessageAsync(RecoveryGrainDto recover, HubRequestContext context) + { + await _distributedEventBus.PublishAsync(new AccountRecoverCompletedEto + { + RecoveryCompletedMessage = new RecoveryCompletedMessageDto + { + RecoveryStatus = GetAccountStatus(recover.RecoverySuccess), + RecoveryMessage = recover.RecoveryMessage, + CaHash = recover.CaHash, + CaAddress = recover.CaAddress + }, + Context = context + }); + } + + private string GetAccountStatus(bool? accountSuccess) => !accountSuccess.HasValue + ? AccountOperationStatus.Pending + : accountSuccess.Value + ? AccountOperationStatus.Pass + : AccountOperationStatus.Fail; + + private async Task SwapGrainStateAsync(string caHash, string grainId) + { + var newDeviceGrain = _clusterClient.GetGrain(GrainIdHelper.GenerateGrainId("Device", caHash)); + var prevDeviceGrain = _clusterClient.GetGrain(GrainIdHelper.GenerateGrainId("Device", grainId)); + var salt = await prevDeviceGrain.GetOrGenerateSaltAsync(); + await newDeviceGrain.SetSaltAsync(salt); + } + + private async Task AddGrowthInfoAsync(string caHash, ReferralInfo referralInfo) + { + if (referralInfo == null || referralInfo.ReferralCode.IsNullOrEmpty()) + { + _logger.LogInformation("no need to add growth info, caHash:{caHash}", caHash); + return; + } + + await _growthAppService.CreateGrowthInfoAsync(caHash, referralInfo); + _logger.LogInformation( + "create growth info success, caHash:{caHash}, referralCode:{referralCode}, projectCode:{projectCode}", + caHash, referralInfo.ReferralCode, referralInfo.ProjectCode ?? string.Empty); + } + + private async Task PublicRegisterMessageAsync(RegisterGrainDto register, HubRequestContext Context) + { + await _distributedEventBus.PublishAsync(new AccountRegisterCompletedEto + { + RegisterCompletedMessage = new RegisterCompletedMessageDto + { + RegisterStatus = GetAccountStatus(register.RegisterSuccess), + CaAddress = register.CaAddress, + CaHash = register.CaHash, + RegisterMessage = register.RegisterMessage + }, + Context = Context + }); + + await _distributedEventBus.PublishAsync(new HolderExtraInfoCompletedEto + { + Status = GetAccountStatus(register.RegisterSuccess), + CaAddress = register.CaAddress, + CaHash = register.CaHash, + GrainId = register.GrainId + }); + } + + private async Task RegisterAlertAsync(AccountRegisterIndex registerIndex) + { + if (!registerIndex.RegisterSuccess == false) return; + + var title = "Register Error"; + _ = _businessAlertProvider.SendWebhookAsync(registerIndex.Id.ToString(), title, + registerIndex.RegisterMessage ?? "-", + JsonConvert.SerializeObject(registerIndex)); + } + + private async Task RecoverAlertAsync(AccountRecoverIndex recoverIndex) + { + if (!recoverIndex.RecoverySuccess == false) return; + + var title = "Register Error"; + _ = _businessAlertProvider.SendWebhookAsync(recoverIndex.Id.ToString(), title, + recoverIndex.RecoveryMessage ?? "-", + JsonConvert.SerializeObject(recoverIndex)); + } +} \ No newline at end of file diff --git a/src/CAServer.EntityEventHandler.Core/Service/CaHolderService.cs b/src/CAServer.EntityEventHandler.Core/Service/CaHolderService.cs new file mode 100644 index 000000000..e798de578 --- /dev/null +++ b/src/CAServer.EntityEventHandler.Core/Service/CaHolderService.cs @@ -0,0 +1,422 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using AElf.Indexing.Elasticsearch; +using CAServer.CAAccount.Provider; +using CAServer.Contacts; +using CAServer.Contacts.Provider; +using CAServer.Entities.Es; +using CAServer.Etos; +using CAServer.Grains.Grain.Contacts; +using CAServer.Guardian; +using CAServer.Guardian.Provider; +using CAServer.Options; +using CAServer.Tokens; +using CAServer.Tokens.Dtos; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Nest; +using Newtonsoft.Json; +using Orleans; +using Volo.Abp.DependencyInjection; +using Volo.Abp.ObjectMapping; +using GuardianInfoBase = CAServer.Guardian.GuardianInfoBase; +using GuardianType = CAServer.Account.GuardianType; + +namespace CAServer.EntityEventHandler.Core.Service; + +public interface ICaHolderService +{ + Task CreateUserAsync(CreateUserEto eventData); + Task UpdateCaHolderAsync(UpdateCAHolderEto eventData); + Task DeleteCaHolderAsync(DeleteCAHolderEto eventData); +} + +public class CaHolderService : ICaHolderService, ISingletonDependency +{ + private readonly INESTRepository _caHolderRepository; + private readonly IObjectMapper _objectMapper; + private readonly ILogger _logger; + private readonly IClusterClient _clusterClient; + private readonly IUserTokenAppService _userTokenAppService; + private readonly IContactProvider _contactProvider; + private readonly INESTRepository _contactRepository; + private readonly IGuardianProvider _guardianProvider; + private readonly INESTRepository _userExtraInfoRepository; + private readonly INESTRepository _guardianRepository; + private readonly IGuardianAppService _guardianAppService; + private readonly IUserProfilePictureProvider _userProfilePictureProvider; + private readonly Random _random; + private readonly IContactAppService _contactAppService; + + public CaHolderService(INESTRepository caHolderRepository, + IObjectMapper objectMapper, + ILogger logger, + IClusterClient clusterClient, + IUserTokenAppService userTokenAppService, + IContactProvider contactProvider, + INESTRepository contactRepository, + IGuardianProvider guardianProvider, + INESTRepository userExtraInfoRepository, + INESTRepository guardianRepository, + IGuardianAppService guardianAppService, + IUserProfilePictureProvider userProfilePictureProvider, + IContactAppService contactAppService) + { + _caHolderRepository = caHolderRepository; + _objectMapper = objectMapper; + _logger = logger; + _clusterClient = clusterClient; + _userTokenAppService = userTokenAppService; + _contactProvider = contactProvider; + _contactRepository = contactRepository; + _guardianProvider = guardianProvider; + _userExtraInfoRepository = userExtraInfoRepository; + _guardianRepository = guardianRepository; + _guardianAppService = guardianAppService; + _userProfilePictureProvider = userProfilePictureProvider; + _contactAppService = contactAppService; + _random = new Random(); + } + + public async Task CreateUserAsync(CreateUserEto eventData) + { + var changedNickname = string.Empty; + var identifierHash = string.Empty; + var nickname = eventData.UserId.ToString("N").Substring(0, 8); + try + { + var loginGuardianInfoBase = await GetLoginAccountInfo(eventData.CaHash); + if (loginGuardianInfoBase == null) + { + var (name, hash) = await GenerateNewAccountFormatForThirdParty(nickname, eventData); + changedNickname = name; + identifierHash = hash; + } + else + { + changedNickname = await GenerateNewAccountFormat(nickname, loginGuardianInfoBase); + identifierHash = loginGuardianInfoBase.IdentifierHash; + } + } + catch (Exception e) + { + _logger.LogError(e, "GenerateNewAccountFormat error, userId={0}, caHash={1}", eventData.UserId, + eventData.CaHash); + } + + try + { + var grain = _clusterClient.GetGrain(eventData.UserId); + var caHolderGrainDto = _objectMapper.Map(eventData); + var pictures = _userProfilePictureProvider.GetDefaultUserPictures(); + string picture; + if (!pictures.IsNullOrEmpty()) + { + picture = pictures[_random.Next(pictures.Count)]; + } + else + { + picture = string.Empty; + } + + if (changedNickname.IsNullOrEmpty() || nickname.Equals(changedNickname)) + { + caHolderGrainDto.Nickname = nickname; + caHolderGrainDto.PopedUp = false; + caHolderGrainDto.ModifiedNickname = false; + caHolderGrainDto.Avatar = picture; + } + else + { + caHolderGrainDto.Nickname = changedNickname; + caHolderGrainDto.PopedUp = true; + caHolderGrainDto.ModifiedNickname = true; + caHolderGrainDto.IdentifierHash = identifierHash; + caHolderGrainDto.Avatar = picture; + } + + var result = await grain.AddHolderWithAvatarAsync(caHolderGrainDto); + if (!result.Success) + { + _logger.LogError("create holder fail: {message}, userId: {userId}, aAHash: {caHash}", result.Message, + eventData.UserId, eventData.CaHash); + return; + } + + var index = _objectMapper.Map(result.Data); + await _caHolderRepository.AddAsync(index); + await _userTokenAppService.AddUserTokenAsync(eventData.UserId, new AddUserTokenInput()); + } + catch (Exception ex) + { + _logger.LogError(ex, "[HandleMessageError] type:{type}, data:{data}, errMsg:{errMsg}", + eventData.GetType().Name, JsonConvert.SerializeObject(eventData), ex.StackTrace ?? "-"); + } + } + + public async Task UpdateCaHolderAsync(UpdateCAHolderEto eventData) + { + try + { + await _caHolderRepository.UpdateAsync(_objectMapper.Map(eventData)); + _logger.LogInformation("caHolder wallet name update success, id: {id}", eventData.Id); + + var contacts = await _contactProvider.GetAddedContactsAsync(eventData.UserId); + if (contacts == null || contacts.Count == 0) return; + + foreach (var contact in contacts) + { + if (contact.CaHolderInfo == null) return; + var grain = _clusterClient.GetGrain(contact.Id); + var updateResult = await grain.UpdateContactInfo(eventData.Nickname, eventData.Avatar); + + if (!updateResult.Success) + { + _logger.LogWarning("contact wallet name update fail, contactId: {id}, message:{message}", + contact.Id, updateResult.Message); + break; + } + + contact.CaHolderInfo.WalletName = eventData.Nickname; + contact.Avatar = eventData.Avatar; + contact.ModificationTime = DateTime.UtcNow; + contact.Index = updateResult.Data.Index; + + await _contactRepository.UpdateAsync(contact); + _logger.LogInformation("contact wallet name update success, contactId: {id}", contact.Id); + } + } + catch (Exception ex) + { + _logger.LogError(ex, "[HandleMessageError] type:{type}, data:{data}, errMsg:{errMsg}", + eventData.GetType().Name, JsonConvert.SerializeObject(eventData), ex.StackTrace ?? "-"); + } + } + + public async Task DeleteCaHolderAsync(DeleteCAHolderEto eventData) + { + try + { + await _caHolderRepository.UpdateAsync(_objectMapper.Map(eventData)); + } + catch (Exception ex) + { + _logger.LogError(ex, "[HandleMessageError] type:{type}, data:{data}, errMsg:{errMsg}", + eventData.GetType().Name, JsonConvert.SerializeObject(eventData), ex.StackTrace ?? "-"); + } + } + + private async Task GetLoginAccountInfo(string caHash) + { + //if the guardian type is third party, the holderInfo is null + var holderInfo = await _guardianProvider.GetGuardiansAsync(null, caHash); + var guardianInfo = holderInfo.CaHolderInfo.FirstOrDefault(g => g.GuardianList != null + && g.GuardianList.Guardians.Count > 0); + if (guardianInfo == null) + { + return null; + } + + var guardianInfoBase = guardianInfo?.GuardianList.Guardians.FirstOrDefault(g => g.IsLoginGuardian); + if (guardianInfoBase == null || !guardianInfoBase.Type.Equals(((int)GuardianType.GUARDIAN_TYPE_OF_EMAIL) + "")) + { + return null; + } + + var list = new List(); + list.Add(guardianInfoBase.IdentifierHash); + var hashDic = await GetIdentifiersAsync(list); + guardianInfoBase.GuardianIdentifier = hashDic[guardianInfoBase.IdentifierHash]; + return guardianInfoBase; + } + + private async Task> GetIdentifiersAsync(List identifierHashList) + { + var mustQuery = new List, QueryContainer>> + { + q => q.Terms(i => i.Field(f => f.IdentifierHash).Terms(identifierHashList)) + }; + + QueryContainer Filter(QueryContainerDescriptor f) => + f.Bool(b => b.Must(mustQuery)); + + var guardians = await _guardianRepository.GetListAsync(Filter); + var result = guardians.Item2.Where(t => t.IsDeleted == false); + return result.ToDictionary(t => t.IdentifierHash, t => t.Identifier); + } + + private async Task GenerateNewAccountFormat(string nickname, GuardianInfoBase guardianInfoBase) + { + if (guardianInfoBase == null) + { + return nickname; + } + + if (!guardianInfoBase.IsLoginGuardian) + { + return nickname; + } + + var guardianIdentifier = guardianInfoBase.GuardianIdentifier; + var guardianType = guardianInfoBase.Type; + if (guardianIdentifier == null) + { + return nickname; + } + + //email according to GuardianType + try + { + if ((int)GuardianType.GUARDIAN_TYPE_OF_EMAIL == int.Parse(guardianType)) + { + if (!guardianIdentifier.Contains("@")) + { + return nickname; + } + + return GetEmailFormat(nickname, guardianIdentifier, string.Empty, string.Empty); + } + } + catch (Exception e) + { + _logger.LogError(e, "GenerateNewAccountFormat error"); + } + + return nickname; + } + + private async Task> GenerateNewAccountFormatForThirdParty(string nickname, + CreateUserEto eventData) + { + if (eventData.ChainId.IsNullOrEmpty() || eventData.CaHash.IsNullOrEmpty()) + { + return new Tuple(nickname, string.Empty); + } + + GuardianResultDto guardianResultDto = null; + try + { + var guardianIdentifierDto = new GuardianIdentifierDto(); + guardianIdentifierDto.ChainId = eventData.ChainId; + guardianIdentifierDto.CaHash = eventData.CaHash; + guardianResultDto = await _guardianAppService.GetGuardianIdentifiersAsync(guardianIdentifierDto); + } + catch (Exception e) + { + _logger.LogError(e, "call GetGuardianIdentifiersAsync error, ChainId={1},CaHash={2}", eventData.ChainId, + eventData.CaHash); + } + + if (guardianResultDto == null) + { + return new Tuple(nickname, string.Empty); + } + + var guardian = guardianResultDto.GuardianList.Guardians.FirstOrDefault(g => g.IsLoginGuardian); + if (guardian == null) + { + return new Tuple(nickname, string.Empty); + } + + string address = string.Empty; + if (!guardianResultDto.CaAddress.IsNullOrEmpty()) + { + address = guardianResultDto.CaAddress; + } + + if ("Telegram".Equals(guardian.Type) || "Twitter".Equals(guardian.Type) || "Facebook".Equals(guardian.Type)) + { + return new Tuple(GetFirstNameFormat(nickname, guardian.FirstName, address), + guardian.IdentifierHash); + } + + if ("Email".Equals(guardian.Type) && !guardian.GuardianIdentifier.IsNullOrEmpty()) + { + return new Tuple( + GetEmailFormat(nickname, guardian.GuardianIdentifier, guardian.FirstName, address), + guardian.IdentifierHash); + } + + return new Tuple( + GetEmailFormat(nickname, guardian.ThirdPartyEmail, guardian.FirstName, address), guardian.IdentifierHash); + } + + private async Task> GetUserExtraInfoAsync(List identifiers) + { + try + { + if (identifiers == null || identifiers.Count == 0) + { + return new List(); + } + + var mustQuery = new List, QueryContainer>> + { + q => q.Terms(i => i.Field(f => f.Id).Terms(identifiers)) + }; + + QueryContainer Filter(QueryContainerDescriptor f) => + f.Bool(b => b.Must(mustQuery)); + + var userExtraInfos = await _userExtraInfoRepository.GetListAsync(Filter); + + return userExtraInfos.Item2; + } + catch (Exception ex) + { + _logger.LogError(ex, "in GetUserExtraInfoAsync"); + } + + return new List(); + } + + private string GetEmailFormat(string nickname, string guardianIdentifier, string firstName, string address) + { + if (guardianIdentifier.IsNullOrEmpty()) + { + return GetFirstNameFormat(nickname, firstName, address); + } + + var index = guardianIdentifier.LastIndexOf("@"); + if (index < 0) + { + return nickname; + } + + var frontPart = guardianIdentifier.Substring(0, index); + var backPart = guardianIdentifier.Substring(index); + var frontLength = frontPart.Length; + if (frontLength > 4) + { + return frontPart.Substring(0, 4) + "***" + backPart; + } + else + { + return frontPart + "***" + backPart; + } + } + + private string GetFirstNameFormat(string nickname, string firstName, string address) + { + if (firstName.IsNullOrEmpty() && address.IsNullOrEmpty()) + { + return nickname; + } + + if (!firstName.IsNullOrEmpty() && Regex.IsMatch(firstName, "^\\w+$")) + { + return firstName + "***"; + } + + if (!address.IsNullOrEmpty()) + { + int length = address.Length; + return address.Substring(0, 3) + "***" + address.Substring(length - 3); + } + + return nickname; + } +} \ No newline at end of file diff --git a/src/CAServer.EntityEventHandler.Core/Service/GuardianService.cs b/src/CAServer.EntityEventHandler.Core/Service/GuardianService.cs new file mode 100644 index 000000000..3b7cc929a --- /dev/null +++ b/src/CAServer.EntityEventHandler.Core/Service/GuardianService.cs @@ -0,0 +1,65 @@ +using System; +using System.Threading.Tasks; +using AElf.Indexing.Elasticsearch; +using CAServer.Entities.Es; +using CAServer.Guardian; +using Microsoft.Extensions.Logging; +using Newtonsoft.Json; +using Volo.Abp.DependencyInjection; +using Volo.Abp.ObjectMapping; + +namespace CAServer.EntityEventHandler.Core.Service; + +public interface IGuardianService +{ + Task AddGuardianAsync(GuardianEto eventData); + Task DeleteGuardianAsync(GuardianDeleteEto eventData); +} + +public class GuardianService : IGuardianService, ISingletonDependency +{ + private readonly INESTRepository _guardianRepository; + private readonly IObjectMapper _objectMapper; + private readonly ILogger _logger; + + public GuardianService( + INESTRepository guardianRepository, + IObjectMapper objectMapper, + ILogger logger) + { + _guardianRepository = guardianRepository; + _objectMapper = objectMapper; + _logger = logger; + } + + public async Task AddGuardianAsync(GuardianEto eventData) + { + try + { + var guardian = _objectMapper.Map(eventData); + await _guardianRepository.AddOrUpdateAsync(guardian); + _logger.LogDebug("Guardian add or update success, id: {id}", eventData.Id); + } + catch (Exception ex) + { + _logger.LogError(ex, "[HandleMessageError] type:{type}, data:{data}, errMsg:{errMsg}", + eventData.GetType().Name, JsonConvert.SerializeObject(eventData), ex.StackTrace ?? "-"); + } + } + + public async Task DeleteGuardianAsync(GuardianDeleteEto eventData) + { + try + { + var guardian = _objectMapper.Map(eventData); + await _guardianRepository.UpdateAsync(guardian); + + _logger.LogDebug("Guardian delete success, id: {id}", eventData.Id); + } + catch (Exception ex) + { + _logger.LogError(ex, "[HandleMessageError] type:{type}, data:{data}, errMsg:{errMsg}", + eventData.GetType().Name, JsonConvert.SerializeObject(eventData), ex.StackTrace ?? "-"); + } + } +} \ No newline at end of file diff --git a/src/CAServer.EntityEventHandler.Core/Service/HolderStatisticService.cs b/src/CAServer.EntityEventHandler.Core/Service/HolderStatisticService.cs new file mode 100644 index 000000000..1eeb79379 --- /dev/null +++ b/src/CAServer.EntityEventHandler.Core/Service/HolderStatisticService.cs @@ -0,0 +1,139 @@ +using System; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using AElf.Indexing.Elasticsearch; +using CAServer.Account; +using CAServer.Entities.Es; +using CAServer.Etos; +using CAServer.IpInfo; +using Microsoft.Extensions.Logging; +using Newtonsoft.Json; +using Volo.Abp.DependencyInjection; +using Volo.Abp.ObjectMapping; + +namespace CAServer.EntityEventHandler.Core.Service; + +public interface IHolderStatisticService +{ + Task HandleHolderExtraInfoAsync(HolderExtraInfoEto eventData); + Task HandleHolderExtraInfoCompletedAsync(HolderExtraInfoCompletedEto eventData); +} + +public class HolderStatisticService : IHolderStatisticService, ISingletonDependency +{ + private readonly INESTRepository _holderStatisticRepository; + private readonly ILogger _logger; + private readonly IIpInfoClient _infoClient; + private readonly IObjectMapper _objectMapper; + + private const string IpPattern = + @"^([0,1]?\d{1,2}|2([0-4][0-9]|5[0-5]))(\.([0,1]?\d{1,2}|2([0-4][0-9]|5[0-5]))){3}$"; + + private const string IpKey = "ip"; + private const string ActivityIdKey = "activityId"; + private const string IpAddressKey = "ipAddress"; + + public HolderStatisticService(INESTRepository holderStatisticRepository, + ILogger logger, IIpInfoClient infoClient, IObjectMapper objectMapper) + { + _holderStatisticRepository = holderStatisticRepository; + _logger = logger; + _infoClient = infoClient; + _objectMapper = objectMapper; + } + + public async Task HandleHolderExtraInfoAsync(HolderExtraInfoEto eventData) + { + try + { + if (eventData.ExtraInfo.IsNullOrEmpty()) return; + + var statisticIndex = new HolderStatisticIndex + { + Id = eventData.GrainId, + OperationType = eventData.OperationType.ToString(), + CreateTime = DateTime.UtcNow, + Status = AccountOperationStatus.Pending.ToString() + }; + + if (eventData.ExtraInfo.TryGetValue(ActivityIdKey, out var activityId)) + { + statisticIndex.ActivityId = activityId.ToString(); + } + + if (eventData.ExtraInfo.TryGetValue(IpAddressKey, out var ipAddress)) + { + statisticIndex.IpAddress = ipAddress.ToString(); + } + + if (eventData.ExtraInfo.TryGetValue(IpKey, out var ip)) + { + statisticIndex.IpAddress = ip.ToString(); + } + + if (!statisticIndex.IpAddress.IsNullOrEmpty()) + { + statisticIndex.CountryInfo = await GetCountryInfoAsync(statisticIndex.IpAddress); + } + + await _holderStatisticRepository.AddOrUpdateAsync(statisticIndex); + _logger.LogInformation( + "save HolderExtraInfo success, grainId:{grainId},ip:{ip},country:{country},activityId:{activityId}", + statisticIndex.Id, statisticIndex.IpAddress ?? "-", statisticIndex.CountryInfo?.CountryName ?? "-", + statisticIndex.ActivityId ?? "-"); + } + catch (Exception e) + { + _logger.LogError(e, "[HandleMessageError] type:{type}, data:{data}, errMsg:{errMsg}", + eventData.GetType().Name, JsonConvert.SerializeObject(eventData), e.StackTrace ?? "-"); + } + } + + public async Task HandleHolderExtraInfoCompletedAsync(HolderExtraInfoCompletedEto eventData) + { + try + { + var statisticIndex = await _holderStatisticRepository.GetAsync(eventData.GrainId); + if (statisticIndex == null) return; + + statisticIndex.CaAddress = eventData.CaAddress; + statisticIndex.CaHash = eventData.CaHash; + statisticIndex.Status = eventData.Status; + + await _holderStatisticRepository.AddOrUpdateAsync(statisticIndex); + _logger.LogInformation( + "save completed HolderExtraInfo success, grainId:{grainId},ip:{ip},country:{country},activityId:{activityId}", + statisticIndex.Id, statisticIndex.IpAddress ?? "-", statisticIndex.CountryInfo?.CountryName ?? "-", + statisticIndex.ActivityId ?? "-"); + } + catch (Exception e) + { + _logger.LogError(e, "[HandleMessageError] type:{type}, data:{data}, errMsg:{errMsg}", + eventData.GetType().Name, JsonConvert.SerializeObject(eventData), e.StackTrace ?? "-"); + } + } + + private async Task GetCountryInfoAsync(string ip) + { + if (!(new Regex(IpPattern).IsMatch(ip))) + { + return null; + } + + var countryInfo = await _infoClient.GetCountryInfoAsync(ip); + if (countryInfo == null) + { + return null; + } + + if (countryInfo.Error != null) + { + _logger.LogError("get ip info error, ip:{0}, error info:{1}", ip, + JsonConvert.SerializeObject(countryInfo.Error)); + return null; + } + + return _objectMapper.Map(countryInfo); + } +} \ No newline at end of file diff --git a/src/CAServer.EntityEventHandler.Core/Service/ReportService.cs b/src/CAServer.EntityEventHandler.Core/Service/ReportService.cs new file mode 100644 index 000000000..e03e2fac1 --- /dev/null +++ b/src/CAServer.EntityEventHandler.Core/Service/ReportService.cs @@ -0,0 +1,53 @@ +using System; +using System.Threading.Tasks; +using AElf.Indexing.Elasticsearch; +using CAServer.DataReporting.Etos; +using CAServer.Entities.Es; +using Microsoft.Extensions.Logging; +using Newtonsoft.Json; +using Volo.Abp.DependencyInjection; +using Volo.Abp.ObjectMapping; + +namespace CAServer.EntityEventHandler.Core.Service; + +public interface IReportService +{ + Task HandleAccountReportAsync(AccountReportEto eventData); +} + +public class ReportService : IReportService, ISingletonDependency +{ + private readonly INESTRepository _repository; + private readonly IObjectMapper _objectMapper; + private readonly ILogger _logger; + + public ReportService(INESTRepository repository, IObjectMapper objectMapper, + ILogger logger) + { + _repository = repository; + _objectMapper = objectMapper; + _logger = logger; + } + + public async Task HandleAccountReportAsync(AccountReportEto eventData) + { + try + { + var index = _objectMapper.Map(eventData); + var reportIndex = await _repository.GetAsync(index.Id); + if (reportIndex == null) + { + index.CreateTime = DateTime.UtcNow; + } + + await _repository.AddOrUpdateAsync(index); + _logger.LogInformation("[AccountReport] account report info handle success, caHash:{caHash}", + eventData.CaHash); + } + catch (Exception e) + { + _logger.LogError(e, "[HandleMessageError] type:{type}, data:{data}, errMsg:{errMsg}", + eventData.GetType().Name, JsonConvert.SerializeObject(eventData), e.StackTrace ?? "-"); + } + } +} \ No newline at end of file diff --git a/src/CAServer.EntityEventHandler.Core/Service/SecondaryEmailService.cs b/src/CAServer.EntityEventHandler.Core/Service/SecondaryEmailService.cs new file mode 100644 index 000000000..0a07b6434 --- /dev/null +++ b/src/CAServer.EntityEventHandler.Core/Service/SecondaryEmailService.cs @@ -0,0 +1,121 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using AElf.Indexing.Elasticsearch; +using CAServer.CAAccount.Provider; +using CAServer.Common; +using CAServer.Entities.Es; +using CAServer.Etos; +using CAServer.Guardian.Provider; +using GraphQL; +using Microsoft.Extensions.Logging; +using Newtonsoft.Json; +using Volo.Abp.DependencyInjection; +using Volo.Abp.ObjectMapping; + +namespace CAServer.EntityEventHandler.Core.Service; + +public interface ISecondaryEmailService +{ + Task HandleAccountEmailAsync(AccountEmailEto eventData); +} + +public class SecondaryEmailService : ISecondaryEmailService, ISingletonDependency +{ + private readonly INESTRepository _guardianRepository; + private readonly IObjectMapper _objectMapper; + private readonly ILogger _logger; + private readonly IGraphQLHelper _graphQlHelper; + private readonly ICAAccountProvider _accountProvider; + + public SecondaryEmailService(INESTRepository guardianRepository, + IObjectMapper objectMapper, + ILogger logger, + IGraphQLHelper graphQlHelper, + ICAAccountProvider accountProvider) + { + _guardianRepository = guardianRepository; + _objectMapper = objectMapper; + _logger = logger; + _graphQlHelper = graphQlHelper; + _accountProvider = accountProvider; + } + + public async Task HandleAccountEmailAsync(AccountEmailEto eventData) + { + if (string.IsNullOrEmpty(eventData.SecondaryEmail) || string.IsNullOrEmpty(eventData.CaHash)) + { + _logger.LogError("SecondaryEmailHandler Params Error received AccountEmailEto:{0}", + JsonConvert.SerializeObject(eventData)); + return; + } + + //1. consumer get guardianList by caHash through GraphQl + var guardiansDto = await GetCaHolderInfoAsync(eventData.CaHash); + if (guardiansDto == null || guardiansDto.CaHolderInfo.IsNullOrEmpty()) + { + _logger.LogError("SecondaryEmailHandler query guardians from graphql failed guardiansDto:{0}", + JsonConvert.SerializeObject(eventData)); + return; + } + + var guardians = guardiansDto.CaHolderInfo + .Where(dto => dto.GuardianList != null) + .Select(dto => dto.GuardianList).ToList(); + foreach (var guardian in guardians.SelectMany(guardianBaseList => guardianBaseList.Guardians)) + { + if (guardian == null) + { + continue; + } + + GuardianIndex guardianIndex = null; + try + { + //2. extract guardian's IdentifierHash, query + guardianIndex = await _accountProvider.GetIdentifiersAsync(guardian.IdentifierHash); + } + catch (Exception e) + { + _logger.LogError(e, "HandleEventAsync get guardianFromGraphQL failed identifierHash:{0}", + guardian.IdentifierHash); + } + + if (guardianIndex == null) + { + continue; + } + + //3、append Guardian's(from es) caHash and secondaryEmail fields + guardianIndex.CaHash = eventData.CaHash; + guardianIndex.SecondaryEmail = eventData.SecondaryEmail; + try + { + await _guardianRepository.AddOrUpdateAsync(guardianIndex); + } + catch (Exception e) + { + _logger.LogError(e, "[HandleMessageError] type:{type}, data:{data}, errMsg:{errMsg}", + eventData.GetType().Name, JsonConvert.SerializeObject(eventData), e.StackTrace ?? "-"); + } + } + } + + private async Task GetCaHolderInfoAsync(string caHash, int skipCount = 0, + int maxResultCount = 10) + { + return await _graphQlHelper.QueryAsync(new GraphQLRequest + { + Query = @" + query($caHash:String,$skipCount:Int!,$maxResultCount:Int!) { + caHolderInfo(dto: {caHash:$caHash,skipCount:$skipCount,maxResultCount:$maxResultCount}){ + id,chainId,caHash,caAddress,originChainId,managerInfos{address,extraData},guardianList{guardians{verifierId,identifierHash,salt,isLoginGuardian,type}}} + }", + Variables = new + { + caHash, skipCount, maxResultCount + } + }); + } +} \ No newline at end of file diff --git a/src/CAServer.EntityEventHandler.Core/Service/TwitterStatisticService.cs b/src/CAServer.EntityEventHandler.Core/Service/TwitterStatisticService.cs new file mode 100644 index 000000000..2080c680d --- /dev/null +++ b/src/CAServer.EntityEventHandler.Core/Service/TwitterStatisticService.cs @@ -0,0 +1,76 @@ +using System; +using System.Threading.Tasks; +using AElf.Indexing.Elasticsearch; +using CAServer.Commons; +using CAServer.Entities.Es; +using CAServer.TwitterAuth.Etos; +using Microsoft.Extensions.Logging; +using Newtonsoft.Json; +using Volo.Abp.DependencyInjection; +using Volo.Abp.ObjectMapping; + +namespace CAServer.EntityEventHandler.Core.Service; + +public interface ITwitterStatisticService +{ + Task StatisticTwitterAsync(TwitterStatisticEto eventData); +} + +public class TwitterStatisticService : ITwitterStatisticService, ISingletonDependency +{ + private readonly INESTRepository _twitterStatisticRepository; + private readonly IObjectMapper _objectMapper; + private readonly ILogger _logger; + + public TwitterStatisticService(IObjectMapper objectMapper, + INESTRepository twitterStatisticRepository, + ILogger logger) + { + _objectMapper = objectMapper; + _twitterStatisticRepository = twitterStatisticRepository; + _logger = logger; + } + + public async Task StatisticTwitterAsync(TwitterStatisticEto eventData) + { + try + { + var item = await _twitterStatisticRepository.GetAsync(eventData.Id); + if (item != null) + { + var date = TimeHelper.GetDateTimeFromSecondTimeStamp(item.UpdateTime); + if (date.Date < DateTime.UtcNow.Date) + { + item.CallCount = 1; + } + else + { + item.CallCount += 1; + } + + item.UpdateTime = eventData.UpdateTime; + await _twitterStatisticRepository.UpdateAsync(item); + + _logger.LogInformation("statistic twitter call api count, userId:{userId}, count:{count}", eventData.Id, + item.CallCount); + + if (item.CallCount > CommonConstant.TwitterLimitCount) + { + _logger.LogWarning("user call twitter api limit, userId:{userId}, count:{count}", eventData.Id, + item.CallCount); + } + + return; + } + + await _twitterStatisticRepository.AddOrUpdateAsync( + _objectMapper.Map(eventData)); + _logger.LogInformation("statistic twitter call api count, userId:{userId}", eventData.Id); + } + catch (Exception e) + { + _logger.LogError(e, "[HandleMessageError] type:{type}, data:{data}, errMsg:{errMsg}", + eventData.GetType().Name, JsonConvert.SerializeObject(eventData), e.StackTrace ?? "-"); + } + } +} \ No newline at end of file diff --git a/src/CAServer.EntityEventHandler.Core/Service/UserTokenService.cs b/src/CAServer.EntityEventHandler.Core/Service/UserTokenService.cs new file mode 100644 index 000000000..3ffcc504b --- /dev/null +++ b/src/CAServer.EntityEventHandler.Core/Service/UserTokenService.cs @@ -0,0 +1,67 @@ +using System; +using System.Threading.Tasks; +using AElf.Indexing.Elasticsearch; +using CAServer.Entities.Es; +using CAServer.Tokens.Etos; +using Microsoft.Extensions.Logging; +using Newtonsoft.Json; +using Volo.Abp.DependencyInjection; +using Volo.Abp.ObjectMapping; + +namespace CAServer.EntityEventHandler.Core.Service; + +public interface IUserTokenService +{ + Task AddTokenAsync(UserTokenEto eventData); + Task DeleteTokenAsync(UserTokenDeleteEto eventData); +} + +public class UserTokenService : IUserTokenService, ISingletonDependency +{ + private readonly INESTRepository _userTokenIndexRepository; + private readonly ILogger _logger; + private readonly IObjectMapper _objectMapper; + + public UserTokenService(INESTRepository userTokenIndexRepository, + ILogger logger, IObjectMapper objectMapper) + { + _userTokenIndexRepository = userTokenIndexRepository; + _logger = logger; + _objectMapper = objectMapper; + } + + public async Task AddTokenAsync(UserTokenEto eventData) + { + _logger.LogInformation("user token is adding.{userId}-{chainId}-{symbol}", eventData.UserId, + eventData.Token.ChainId, eventData.Token.Symbol); + var index = _objectMapper.Map(eventData); + try + { + await _userTokenIndexRepository.AddOrUpdateAsync(index); + _logger.LogInformation("user token add success.{userId}-{chainId}-{symbol}", eventData.UserId, + eventData.Token.ChainId, eventData.Token.Symbol); + } + catch (Exception e) + { + _logger.LogError(e, "[HandleMessageError] type:{type}, data:{data}, errMsg:{errMsg}", + eventData.GetType().Name, JsonConvert.SerializeObject(eventData), e.StackTrace ?? "-"); + } + } + + public async Task DeleteTokenAsync(UserTokenDeleteEto eventData) + { + _logger.LogInformation("user token is deleting.{userId}-{chainId}-{symbol}", eventData.UserId, + eventData.Token.ChainId, eventData.Token.Symbol); + try + { + await _userTokenIndexRepository.DeleteAsync(eventData.Id); + _logger.LogInformation("user token delete success.{userId}-{chainId}-{symbol}", eventData.UserId, + eventData.Token.ChainId, eventData.Token.Symbol); + } + catch (Exception e) + { + _logger.LogError(e, "[HandleMessageError] type:{type}, data:{data}, errMsg:{errMsg}", + eventData.GetType().Name, JsonConvert.SerializeObject(eventData), e.StackTrace ?? "-"); + } + } +} \ No newline at end of file diff --git a/src/CAServer.EntityEventHandler.Core/TwitterStatisticHandler.cs b/src/CAServer.EntityEventHandler.Core/TwitterStatisticHandler.cs index 50442e837..e4942fa87 100644 --- a/src/CAServer.EntityEventHandler.Core/TwitterStatisticHandler.cs +++ b/src/CAServer.EntityEventHandler.Core/TwitterStatisticHandler.cs @@ -1,69 +1,22 @@ -using System; using System.Threading.Tasks; -using AElf.Indexing.Elasticsearch; -using CAServer.Commons; -using CAServer.Entities.Es; +using CAServer.EntityEventHandler.Core.Service; using CAServer.TwitterAuth.Etos; -using Microsoft.Extensions.Logging; using Volo.Abp.DependencyInjection; using Volo.Abp.EventBus.Distributed; -using Volo.Abp.ObjectMapping; namespace CAServer.EntityEventHandler.Core; public class TwitterStatisticHandler : IDistributedEventHandler, ITransientDependency { - private readonly INESTRepository _twitterStatisticRepository; - private readonly IObjectMapper _objectMapper; - private readonly ILogger _logger; + private readonly ITwitterStatisticService _twitterStatisticService; - public TwitterStatisticHandler(IObjectMapper objectMapper, - INESTRepository twitterStatisticRepository, - ILogger logger) + public TwitterStatisticHandler(ITwitterStatisticService twitterStatisticService) { - _objectMapper = objectMapper; - _twitterStatisticRepository = twitterStatisticRepository; - _logger = logger; + _twitterStatisticService = twitterStatisticService; } public async Task HandleEventAsync(TwitterStatisticEto eventData) { - try - { - var item = await _twitterStatisticRepository.GetAsync(eventData.Id); - if (item != null) - { - var date = TimeHelper.GetDateTimeFromSecondTimeStamp(item.UpdateTime); - if (date.Date < DateTime.UtcNow.Date) - { - item.CallCount = 1; - } - else - { - item.CallCount += 1; - } - item.UpdateTime = eventData.UpdateTime; - await _twitterStatisticRepository.UpdateAsync(item); - - _logger.LogInformation("statistic twitter call api count, userId:{userId}, count:{count}", eventData.Id, - item.CallCount); - - if (item.CallCount > CommonConstant.TwitterLimitCount) - { - _logger.LogWarning("user call twitter api limit, userId:{userId}, count:{count}", eventData.Id, - item.CallCount); - } - - return; - } - - await _twitterStatisticRepository.AddOrUpdateAsync( - _objectMapper.Map(eventData)); - _logger.LogInformation("statistic twitter call api count, userId:{userId}", eventData.Id); - } - catch (Exception e) - { - _logger.LogError(e, "statistic twitter call api count error, userId:{userId}", eventData.Id); - } + _ = _twitterStatisticService.StatisticTwitterAsync(eventData); } } \ No newline at end of file diff --git a/src/CAServer.EntityEventHandler.Core/UserBehaviorHandler.cs b/src/CAServer.EntityEventHandler.Core/UserBehaviorHandler.cs index c458c3331..4541397da 100644 --- a/src/CAServer.EntityEventHandler.Core/UserBehaviorHandler.cs +++ b/src/CAServer.EntityEventHandler.Core/UserBehaviorHandler.cs @@ -14,7 +14,7 @@ public class UserBehaviorHandler : IDistributedEventHandler, IT private readonly IObjectMapper _objectMapper; private readonly ILogger _logger; private readonly IUserBehaviorAppService _userBehaviorAppService; - + public UserBehaviorHandler( IObjectMapper objectMapper, ILogger logger, @@ -29,7 +29,7 @@ public async Task HandleEventAsync(UserBehaviorEto eventData) { try { - await _userBehaviorAppService.AddUserBehaviorAsync(eventData); + _ = _userBehaviorAppService.AddUserBehaviorAsync(eventData); } catch (Exception e) { diff --git a/src/CAServer.EntityEventHandler.Core/UserExtraInfoHandler.cs b/src/CAServer.EntityEventHandler.Core/UserExtraInfoHandler.cs index 370293aee..c02fab938 100644 --- a/src/CAServer.EntityEventHandler.Core/UserExtraInfoHandler.cs +++ b/src/CAServer.EntityEventHandler.Core/UserExtraInfoHandler.cs @@ -32,10 +32,8 @@ public async Task HandleEventAsync(UserExtraInfoEto eventData) try { var userInfo = _objectMapper.Map(eventData); - _logger.LogDebug("User extra info add or update: {eventData}", JsonConvert.SerializeObject(userInfo)); await _userExtraInfoRepository.AddOrUpdateAsync(userInfo); - - _logger.LogDebug($"User extra info add or update success: {JsonConvert.SerializeObject(userInfo)}"); + _logger.LogDebug("User extra info add or update success: {data}", JsonConvert.SerializeObject(userInfo)); } catch (Exception ex) { diff --git a/src/CAServer.EntityEventHandler.Core/UserTokenEntityHandler.cs b/src/CAServer.EntityEventHandler.Core/UserTokenEntityHandler.cs index 7a1ef6a27..8360c7d32 100644 --- a/src/CAServer.EntityEventHandler.Core/UserTokenEntityHandler.cs +++ b/src/CAServer.EntityEventHandler.Core/UserTokenEntityHandler.cs @@ -1,10 +1,6 @@ -using System; using System.Threading.Tasks; -using AElf.Indexing.Elasticsearch; -using CAServer.Entities.Es; +using CAServer.EntityEventHandler.Core.Service; using CAServer.Tokens.Etos; -using Microsoft.Extensions.Logging; -using Newtonsoft.Json; using Volo.Abp.EventBus.Distributed; namespace CAServer.EntityEventHandler.Core; @@ -13,46 +9,20 @@ public class UserTokenEntityHandler : EntityHandlerBase, IDistributedEventHandler, IDistributedEventHandler { - private readonly INESTRepository _userTokenIndexRepository; - private readonly ILogger _logger; + private readonly IUserTokenService _userTokenService; - public UserTokenEntityHandler(INESTRepository userTokenIndexRepository, - ILogger logger) + public UserTokenEntityHandler(IUserTokenService userTokenService) { - _userTokenIndexRepository = userTokenIndexRepository; - _logger = logger; + _userTokenService = userTokenService; } public async Task HandleEventAsync(UserTokenEto eventData) { - _logger.LogInformation("user token is adding.{userId}-{chainId}-{symbol}", eventData.UserId, - eventData.Token.ChainId, eventData.Token.Symbol); - var index = ObjectMapper.Map(eventData); - try - { - await _userTokenIndexRepository.AddOrUpdateAsync(index); - _logger.LogInformation("user token add success.{userId}-{chainId}-{symbol}", eventData.UserId, - eventData.Token.ChainId, eventData.Token.Symbol); - } - catch (Exception ex) - { - _logger.LogError(ex, "{Message}", JsonConvert.SerializeObject(eventData)); - } + _ = _userTokenService.AddTokenAsync(eventData); } public async Task HandleEventAsync(UserTokenDeleteEto eventData) { - _logger.LogInformation("user token is deleting.{userId}-{chainId}-{symbol}", eventData.UserId, - eventData.Token.ChainId, eventData.Token.Symbol); - try - { - await _userTokenIndexRepository.DeleteAsync(eventData.Id); - _logger.LogInformation("user token delete success.{userId}-{chainId}-{symbol}", eventData.UserId, - eventData.Token.ChainId, eventData.Token.Symbol); - } - catch (Exception ex) - { - _logger.LogError(ex, "{Message}", JsonConvert.SerializeObject(eventData)); - } + _ = _userTokenService.DeleteTokenAsync(eventData); } } \ No newline at end of file From 16b61305d36b0f3fe3ae68c9e6412966993a120d Mon Sep 17 00:00:00 2001 From: felix-zhao <123852192+felix-zhaolei@users.noreply.github.com> Date: Wed, 18 Dec 2024 17:19:29 +0800 Subject: [PATCH 2/3] Access node optimization (#1022) * feat: request to node. --- .../Commons/AelfClientConstant.cs | 7 + .../CAServerApplicationModule.cs | 3 + .../Common/AelfClient/IContractClient.cs | 28 +++ .../AelfClient/IContractClientSelector.cs | 28 +++ .../AelfClient/MainChainContractClient.cs | 185 ++++++++++++++++++ .../AelfClient/SideChainContractClient.cs | 185 ++++++++++++++++++ .../ContractService/ContractService.cs | 21 +- .../Application/IContractProvider.cs | 51 +++-- .../CAServerContractEventHandlerCoreModule.cs | 4 + .../CAServerContractEventHandlerModule.cs | 27 +++ .../appsettings.json | 6 +- 11 files changed, 516 insertions(+), 29 deletions(-) create mode 100644 src/CAServer.Application.Contracts/Commons/AelfClientConstant.cs create mode 100644 src/CAServer.Application/Common/AelfClient/IContractClient.cs create mode 100644 src/CAServer.Application/Common/AelfClient/IContractClientSelector.cs create mode 100644 src/CAServer.Application/Common/AelfClient/MainChainContractClient.cs create mode 100644 src/CAServer.Application/Common/AelfClient/SideChainContractClient.cs diff --git a/src/CAServer.Application.Contracts/Commons/AelfClientConstant.cs b/src/CAServer.Application.Contracts/Commons/AelfClientConstant.cs new file mode 100644 index 000000000..ff1a0d0e0 --- /dev/null +++ b/src/CAServer.Application.Contracts/Commons/AelfClientConstant.cs @@ -0,0 +1,7 @@ +namespace CAServer.Commons; + +public static class AelfClientConstant +{ + public const string MainChainClient = "MainChainClient"; + public const string SideChainClient = "SideChainClient"; +} \ No newline at end of file diff --git a/src/CAServer.Application/CAServerApplicationModule.cs b/src/CAServer.Application/CAServerApplicationModule.cs index 5e7413972..7633e2245 100644 --- a/src/CAServer.Application/CAServerApplicationModule.cs +++ b/src/CAServer.Application/CAServerApplicationModule.cs @@ -6,6 +6,7 @@ using CAServer.CAAccount.Provider; using CAServer.Cache; using CAServer.Common; +using CAServer.Common.AelfClient; using CAServer.Commons; using CAServer.CryptoGift; using CAServer.DataReporting; @@ -173,6 +174,8 @@ public override void ConfigureServices(ServiceConfigurationContext context) context.Services.AddScoped(); context.Services.AddScoped(); context.Services.AddSingleton(); + context.Services.AddSingleton(); + context.Services.AddSingleton(); Configure(configuration.GetSection("Variables")); context.Services.AddScoped(); diff --git a/src/CAServer.Application/Common/AelfClient/IContractClient.cs b/src/CAServer.Application/Common/AelfClient/IContractClient.cs new file mode 100644 index 000000000..4b1f028b1 --- /dev/null +++ b/src/CAServer.Application/Common/AelfClient/IContractClient.cs @@ -0,0 +1,28 @@ +using System; +using System.Linq; +using System.Net.Http; +using System.Threading.Tasks; +using AElf.Client.Dto; +using AElf.Types; +using Google.Protobuf; + +namespace CAServer.Common.AelfClient; + +public interface IContractClient +{ + Task GenerateTransactionAsync( + string from, + string to, + string methodName, + IMessage input); + + Task GetBlockByHeightAsync(long blockHeight, bool includeTransactions = false); + + Task SendTransactionAsync(SendTransactionInput input); + + Task GetTransactionResultAsync(string transactionId); + Task ExecuteTransactionAsync(ExecuteTransactionDto input); + + Transaction SignTransaction(string privateKeyHex, Transaction transaction); +} + diff --git a/src/CAServer.Application/Common/AelfClient/IContractClientSelector.cs b/src/CAServer.Application/Common/AelfClient/IContractClientSelector.cs new file mode 100644 index 000000000..590c81eeb --- /dev/null +++ b/src/CAServer.Application/Common/AelfClient/IContractClientSelector.cs @@ -0,0 +1,28 @@ +using System.Collections.Generic; +using System.Linq; +using CAServer.Commons; +using Volo.Abp.DependencyInjection; + +namespace CAServer.Common.AelfClient; + +public interface IContractClientSelector +{ + IContractClient GetContractClient(string chainId); +} + +public class ContractClientSelector : IContractClientSelector, ISingletonDependency +{ + private readonly IEnumerable _contractClients; + + public ContractClientSelector(IEnumerable contractClients) + { + _contractClients = contractClients; + } + + public IContractClient GetContractClient(string chainId) + { + return chainId == CommonConstant.MainChainId + ? _contractClients.FirstOrDefault(t => t.GetType().Name == nameof(MainChainContractClient)) + : _contractClients.FirstOrDefault(t => t.GetType().Name == nameof(SideChainContractClient)); + } +} \ No newline at end of file diff --git a/src/CAServer.Application/Common/AelfClient/MainChainContractClient.cs b/src/CAServer.Application/Common/AelfClient/MainChainContractClient.cs new file mode 100644 index 000000000..c9c8c76ba --- /dev/null +++ b/src/CAServer.Application/Common/AelfClient/MainChainContractClient.cs @@ -0,0 +1,185 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Net.Mime; +using System.Text; +using System.Threading.Tasks; +using AElf; +using AElf.Client.Dto; +using AElf.Cryptography; +using AElf.Types; +using CAServer.Commons; +using Google.Protobuf; +using Microsoft.Extensions.Logging; +using Newtonsoft.Json; +using Volo.Abp; + +namespace CAServer.Common.AelfClient; + +public class MainChainContractClient : IContractClient +{ + private readonly IHttpClientFactory _httpClientFactory; + private readonly ILogger _logger; + + public MainChainContractClient(IHttpClientFactory httpClientFactory, ILogger logger) + { + _httpClientFactory = httpClientFactory; + _logger = logger; + } + + public async Task GenerateTransactionAsync( + string from, + string to, + string methodName, + IMessage input) + { + try + { + var chainStatusAsync = await GetChainStatusAsync(); + return new Transaction() + { + From = Address.FromBase58(from), + To = Address.FromBase58(to), + MethodName = methodName, + Params = input.ToByteString(), + RefBlockNumber = chainStatusAsync.BestChainHeight, + RefBlockPrefix = ByteString.CopyFrom(Hash.LoadFromHex(chainStatusAsync.BestChainHash).Value + .Take(4).ToArray()) + }; + } + catch (Exception ex) + { + _logger.LogError(ex, "[ContractClient.GenerateTransactionAsync] error, msg:{0},trace:{1}", ex.Message, + ex.StackTrace ?? "-"); + return (Transaction)null; + } + } + + public async Task GetBlockByHeightAsync(long blockHeight, bool includeTransactions = false) + { + var uri = string.Format("api/blockChain/blockByHeight?blockHeight={0}&includeTransactions={1}", + blockHeight, includeTransactions); + return await GetAsync(uri); + } + + public async Task SendTransactionAsync(SendTransactionInput input) + { + var uri = "api/blockChain/sendTransaction"; + var param = new Dictionary() + { + { + "RawTransaction", + input.RawTransaction + } + }; + return await PostAsync(uri, param); + } + + public async Task GetTransactionResultAsync(string transactionId) + { + var url = "api/blockChain/transactionResult?transactionId=" + transactionId; + return await GetAsync(url); + } + + public async Task ExecuteTransactionAsync(ExecuteTransactionDto input) + { + var url = "api/blockChain/executeTransaction"; + var param = new Dictionary() + { + { + "RawTransaction", + input.RawTransaction + } + }; + return await PostAsync(url, param); + } + + public Transaction SignTransaction(string privateKeyHex, Transaction transaction) + { + byte[] byteArray = transaction.GetHash().ToByteArray(); + byte[] numArray = + CryptoHelper.SignWithPrivateKey(ByteArrayHelper.HexStringToByteArray(privateKeyHex), byteArray); + transaction.Signature = ByteString.CopyFrom(numArray); + return transaction; + } + + public async Task GetChainStatusAsync() + { + var uri = "api/blockChain/chainStatus"; + return await GetAsync(uri); + } + + public async Task GetAsync(string url) + { + var client = _httpClientFactory.CreateClient(AelfClientConstant.MainChainClient); + var response = await client.GetAsync(url); + var content = await response.Content.ReadAsStringAsync(); + if (!ResponseSuccess(response.StatusCode)) + { + _logger.LogError( + "[ContractClientError] MainChainContractClient GetError Response not success, url:{url}, code:{code}, message: {message}", + url, response.StatusCode, content); + + throw new UserFriendlyException(content, ((int)response.StatusCode).ToString()); + } + + return JsonConvert.DeserializeObject(content); + } + + public async Task PostAsync(string url, object paramObj) + { + var requestInput = paramObj == null ? string.Empty : JsonConvert.SerializeObject(paramObj, Formatting.None); + + var requestContent = new StringContent( + requestInput, + Encoding.UTF8, + MediaTypeNames.Application.Json); + + var client = _httpClientFactory.CreateClient(AelfClientConstant.MainChainClient); + + var response = await client.PostAsync(url, requestContent); + var content = await response.Content.ReadAsStringAsync(); + + if (!ResponseSuccess(response.StatusCode)) + { + _logger.LogError( + "[ContractClientError] MainChainContractClient PostError Response not success, url:{url}, code:{code}, message: {message}, params:{param}", + url, response.StatusCode, content, JsonConvert.SerializeObject(paramObj)); + + throw new UserFriendlyException(content, ((int)response.StatusCode).ToString()); + } + + return JsonConvert.DeserializeObject(content); + } + + public async Task PostAsync(string url, object paramObj) + { + var requestInput = paramObj == null ? string.Empty : JsonConvert.SerializeObject(paramObj, Formatting.None); + + var requestContent = new StringContent( + requestInput, + Encoding.UTF8, + MediaTypeNames.Application.Json); + + var client = _httpClientFactory.CreateClient(AelfClientConstant.MainChainClient); + + var response = await client.PostAsync(url, requestContent); + var content = await response.Content.ReadAsStringAsync(); + + if (!ResponseSuccess(response.StatusCode)) + { + _logger.LogError( + "[ContractClientError] MainChainContractClient PostError Response not success, url:{url}, code:{code}, message: {message}, params:{param}", + url, response.StatusCode, content, JsonConvert.SerializeObject(paramObj)); + + throw new UserFriendlyException(content, ((int)response.StatusCode).ToString()); + } + + return content; + } + + private bool ResponseSuccess(HttpStatusCode statusCode) => + statusCode is HttpStatusCode.OK or HttpStatusCode.NoContent; +} \ No newline at end of file diff --git a/src/CAServer.Application/Common/AelfClient/SideChainContractClient.cs b/src/CAServer.Application/Common/AelfClient/SideChainContractClient.cs new file mode 100644 index 000000000..6875c72e6 --- /dev/null +++ b/src/CAServer.Application/Common/AelfClient/SideChainContractClient.cs @@ -0,0 +1,185 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Net.Mime; +using System.Text; +using System.Threading.Tasks; +using AElf; +using AElf.Client.Dto; +using AElf.Cryptography; +using AElf.Types; +using CAServer.Commons; +using Google.Protobuf; +using Microsoft.Extensions.Logging; +using Newtonsoft.Json; +using Volo.Abp; + +namespace CAServer.Common.AelfClient; + +public class SideChainContractClient : IContractClient +{ + private readonly IHttpClientFactory _httpClientFactory; + private readonly ILogger _logger; + + public SideChainContractClient(IHttpClientFactory httpClientFactory, ILogger logger) + { + _httpClientFactory = httpClientFactory; + _logger = logger; + } + + public async Task GenerateTransactionAsync( + string from, + string to, + string methodName, + IMessage input) + { + try + { + var chainStatusAsync = await GetChainStatusAsync(); + return new Transaction() + { + From = Address.FromBase58(from), + To = Address.FromBase58(to), + MethodName = methodName, + Params = input.ToByteString(), + RefBlockNumber = chainStatusAsync.BestChainHeight, + RefBlockPrefix = ByteString.CopyFrom(Hash.LoadFromHex(chainStatusAsync.BestChainHash).Value + .Take(4).ToArray()) + }; + } + catch (Exception ex) + { + _logger.LogError(ex, "[ContractClient.GenerateTransactionAsync] SideChainContractClient error, msg:{0},trace:{1}", ex.Message, + ex.StackTrace ?? "-"); + return (Transaction)null; + } + } + + public async Task GetBlockByHeightAsync(long blockHeight, bool includeTransactions = false) + { + var uri = string.Format("api/blockChain/blockByHeight?blockHeight={0}&includeTransactions={1}", + blockHeight, includeTransactions); + return await GetAsync(uri); + } + + public async Task SendTransactionAsync(SendTransactionInput input) + { + var uri = "api/blockChain/sendTransaction"; + var param = new Dictionary() + { + { + "RawTransaction", + input.RawTransaction + } + }; + return await PostAsync(uri, param); + } + + public async Task GetTransactionResultAsync(string transactionId) + { + var url = "api/blockChain/transactionResult?transactionId=" + transactionId; + return await GetAsync(url); + } + + public async Task ExecuteTransactionAsync(ExecuteTransactionDto input) + { + var url = "api/blockChain/executeTransaction"; + var param = new Dictionary() + { + { + "RawTransaction", + input.RawTransaction + } + }; + return await PostAsync(url, param); + } + + public Transaction SignTransaction(string privateKeyHex, Transaction transaction) + { + byte[] byteArray = transaction.GetHash().ToByteArray(); + byte[] numArray = + CryptoHelper.SignWithPrivateKey(ByteArrayHelper.HexStringToByteArray(privateKeyHex), byteArray); + transaction.Signature = ByteString.CopyFrom(numArray); + return transaction; + } + + public async Task GetChainStatusAsync() + { + var uri = "api/blockChain/chainStatus"; + return await GetAsync(uri); + } + + public async Task GetAsync(string url) + { + var client = _httpClientFactory.CreateClient(AelfClientConstant.SideChainClient); + var response = await client.GetAsync(url); + var content = await response.Content.ReadAsStringAsync(); + if (!ResponseSuccess(response.StatusCode)) + { + _logger.LogError( + "[ContractClientError] SideChainContractClient GetError Response not success, url:{url}, code:{code}, message: {message}", + url, response.StatusCode, content); + + throw new UserFriendlyException(content, ((int)response.StatusCode).ToString()); + } + + return JsonConvert.DeserializeObject(content); + } + + public async Task PostAsync(string url, object paramObj) + { + var requestInput = paramObj == null ? string.Empty : JsonConvert.SerializeObject(paramObj, Formatting.None); + + var requestContent = new StringContent( + requestInput, + Encoding.UTF8, + MediaTypeNames.Application.Json); + + var client = _httpClientFactory.CreateClient(AelfClientConstant.SideChainClient); + + var response = await client.PostAsync(url, requestContent); + var content = await response.Content.ReadAsStringAsync(); + + if (!ResponseSuccess(response.StatusCode)) + { + _logger.LogError( + "[ContractClientError] SideChainContractClient PostError Response not success, url:{url}, code:{code}, message: {message}, params:{param}", + url, response.StatusCode, content, JsonConvert.SerializeObject(paramObj)); + + throw new UserFriendlyException(content, ((int)response.StatusCode).ToString()); + } + + return JsonConvert.DeserializeObject(content); + } + + public async Task PostAsync(string url, object paramObj) + { + var requestInput = paramObj == null ? string.Empty : JsonConvert.SerializeObject(paramObj, Formatting.None); + + var requestContent = new StringContent( + requestInput, + Encoding.UTF8, + MediaTypeNames.Application.Json); + + var client = _httpClientFactory.CreateClient(AelfClientConstant.SideChainClient); + + var response = await client.PostAsync(url, requestContent); + var content = await response.Content.ReadAsStringAsync(); + + if (!ResponseSuccess(response.StatusCode)) + { + _logger.LogError( + "[ContractClientError] SideChainContractClient PostError Response not success, url:{url}, code:{code}, message: {message}, params:{param}", + url, response.StatusCode, content, JsonConvert.SerializeObject(paramObj)); + + throw new UserFriendlyException(content, ((int)response.StatusCode).ToString()); + } + + return content; + } + + private bool ResponseSuccess(HttpStatusCode statusCode) => + statusCode is HttpStatusCode.OK or HttpStatusCode.NoContent; +} \ No newline at end of file diff --git a/src/CAServer.Application/ContractService/ContractService.cs b/src/CAServer.Application/ContractService/ContractService.cs index c950fe56d..ba31c494e 100644 --- a/src/CAServer.Application/ContractService/ContractService.cs +++ b/src/CAServer.Application/ContractService/ContractService.cs @@ -7,6 +7,8 @@ using AElf.Types; using CAServer.CAAccount; using CAServer.CAAccount.Dtos; +using CAServer.Common; +using CAServer.Common.AelfClient; using CAServer.Commons; using CAServer.Grains.Grain.ApplicationHandler; using CAServer.Grains.State.ApplicationHandler; @@ -36,10 +38,11 @@ public class ContractService : IContractService, ISingletonDependency private readonly ISignatureProvider _signatureProvider; private readonly IIndicatorScope _indicatorScope; private readonly IDistributedEventBus _distributedEventBus; + private readonly IContractClientSelector _contractClientSelector; public ContractService(IOptions chainOptions, IOptions contractGrainOptions, IObjectMapper objectMapper, ISignatureProvider signatureProvider, ILogger logger, - IIndicatorScope indicatorScope, IDistributedEventBus distributedEventBus) + IIndicatorScope indicatorScope, IDistributedEventBus distributedEventBus, IContractClientSelector contractClientSelector) { _objectMapper = objectMapper; _logger = logger; @@ -48,6 +51,7 @@ public ContractService(IOptions chainOptions, IOptions SendTransactionToChainAsync(string chainId, IMessage param, @@ -60,9 +64,11 @@ private async Task SendTransactionToChainAsync(string chainI return null; } - var client = new AElfClient(chainInfo.BaseUrl); - await client.IsConnectedAsync(); - var ownAddress = client.GetAddressFromPubKey(chainInfo.PublicKey); + //var client = new AElfClient(chainInfo.BaseUrl); + var client = _contractClientSelector.GetContractClient(chainId); + //var ownAddress = client.GetAddressFromPubKey(chainInfo.PublicKey); + var ownAddress = Address.FromPublicKey(ByteArrayHelper.HexStringToByteArray(chainInfo.PublicKey)) + .ToBase58(); _logger.LogDebug("Get Address From PubKey, ownAddress:{ownAddress}, ContractAddress: {ContractAddress} ", ownAddress, chainInfo.ContractAddress); var interIndicator = _indicatorScope.Begin(MonitorTag.AelfClient, @@ -117,6 +123,7 @@ await client.GenerateTransactionAsync(ownAddress, chainInfo.ContractAddress, met _indicatorScope.End(retryGetIndicator); } + return new TransactionInfoDto { Transaction = transaction, @@ -150,7 +157,7 @@ private async Task ForwardTransactionToChainAsync(string cha await Task.Delay(_contractServiceOptions.Delay); var transactionResult = await client.GetTransactionResultAsync(result.TransactionId); - + var times = 0; while ((transactionResult.Status == TransactionState.Pending || transactionResult.Status == TransactionState.NotExisted) && @@ -160,7 +167,7 @@ private async Task ForwardTransactionToChainAsync(string cha await Task.Delay(_contractServiceOptions.CryptoBoxRetryDelay); transactionResult = await client.GetTransactionResultAsync(result.TransactionId); } - + return new TransactionInfoDto { TransactionResultDto = transactionResult @@ -401,7 +408,7 @@ await client.GenerateTransactionAsync(ownAddress, redPackageContractAddress, met var transactionResult = await client.GetTransactionResultAsync(result.TransactionId); _logger.LogInformation("SendTransferRedPacketToChainAsync transactionResult: {transactionResult}", JsonConvert.SerializeObject(transactionResult)); - + var times = 0; while ((transactionResult.Status == TransactionState.Pending || transactionResult.Status == TransactionState.NotExisted) && diff --git a/src/CAServer.ContractEventHandler.Core/Application/IContractProvider.cs b/src/CAServer.ContractEventHandler.Core/Application/IContractProvider.cs index 4e39a2dd9..33221eed8 100644 --- a/src/CAServer.ContractEventHandler.Core/Application/IContractProvider.cs +++ b/src/CAServer.ContractEventHandler.Core/Application/IContractProvider.cs @@ -7,6 +7,7 @@ using AElf.Client.Service; using AElf.Types; using CAServer.CAAccount.Dtos; +using CAServer.Common.AelfClient; using CAServer.Grains.Grain; using CAServer.Commons; using CAServer.ContractService; @@ -86,12 +87,14 @@ public class ContractProvider : IContractProvider private readonly IDistributedCache _distributedCache; private readonly BlockInfoOptions _blockInfoOptions; private readonly ContractServiceProxy _contractServiceProxy; + private readonly IContractClientSelector _contractClientSelector; public ContractProvider(ILogger logger, IOptionsSnapshot chainOptions, IOptionsSnapshot indexOptions, IClusterClient clusterClient, ISignatureProvider signatureProvider, IGraphQLProvider graphQlProvider, IIndicatorScope indicatorScope, IDistributedCache distributedCache, - IOptionsSnapshot blockInfoOptions, ContractServiceProxy contractServiceProxy) + IOptionsSnapshot blockInfoOptions, ContractServiceProxy contractServiceProxy, + IContractClientSelector contractClientSelector) { _logger = logger; _chainOptions = chainOptions.Value; @@ -102,6 +105,7 @@ public ContractProvider(ILogger logger, IOptionsSnapshot CallTransactionAsync(string chainId, string methodName, { var chainInfo = _chainOptions.ChainInfos[chainId]; - var client = new AElfClient(chainInfo.BaseUrl); - await client.IsConnectedAsync(); - var ownAddress = client.GetAddressFromPubKey(chainInfo.PublicKey); + //var client = new AElfClient(chainInfo.BaseUrl); + var client = _contractClientSelector.GetContractClient(chainId); + var ownAddress = Address.FromPublicKey(ByteArrayHelper.HexStringToByteArray(chainInfo.PublicKey)) + .ToBase58(); var contractAddress = isCrossChain ? chainInfo.CrossChainContractAddress : chainInfo.ContractAddress; var generateIndicator = _indicatorScope.Begin(MonitorTag.AelfClient, @@ -145,7 +150,9 @@ await client.GenerateTransactionAsync(ownAddress, contractAddress, { if (methodName != MethodName.GetHolderInfo) { - _logger.LogError(e, methodName + " error: {param}", param); + _logger.LogError(e, + "CallTransactionAsync error, chainId:{chainId}, methodName:{methodName}, param:{param}, msg:{msg}", + chainId, methodName, param, e.Message); } return new T(); @@ -251,7 +258,8 @@ public async Task GetTransactionResultAsync(string chainId } catch (Exception e) { - _logger.LogError(e, "GetTransactionResult on chain {chainId} with txId: {txId} error", chainId, txId); + _logger.LogError(e, "GetTransactionResult on chain {chainId} with txId: {txId} error, msg:{msg}", chainId, + txId, e.Message); return new TransactionResultDto(); } } @@ -293,8 +301,7 @@ public async Task CreateHolderInfoAsync(CreateHolderDto cr var result = await _contractServiceProxy.CreateHolderInfoAsync(createHolderDto); _logger.LogInformation( - "CreateHolderInfo to chain: {id} result:" + - "\nTransactionId: {transactionId}, BlockNumber: {number}, Status: {status}, ErrorInfo: {error}", + "CreateHolderInfo to chain: {id} result: TransactionId: {transactionId}, BlockNumber: {number}, Status: {status}, ErrorInfo: {error}", createHolderDto.ChainId, result.TransactionId, result.BlockNumber, result.Status, result.Error); @@ -302,7 +309,8 @@ public async Task CreateHolderInfoAsync(CreateHolderDto cr } catch (Exception e) { - _logger.LogError(e, "CreateHolderInfo error: {message}", JsonConvert.SerializeObject(createHolderDto.ToString())); + _logger.LogError(e, "CreateHolderInfo error: {message}", + JsonConvert.SerializeObject(createHolderDto)); return new TransactionResultDto { Status = TransactionState.Failed, @@ -343,7 +351,8 @@ public async Task CreateHolderInfoOnNonCreateChainAsync(Ch createHolderDto.CaHash = outputGetHolderInfo.CaHash; createHolderDto.ChainId = createChainId; - var result = await _contractServiceProxy.CreateHolderInfoOnNonCreateChainAsync(chainInfo.ChainId, createHolderDto); + var result = + await _contractServiceProxy.CreateHolderInfoOnNonCreateChainAsync(chainInfo.ChainId, createHolderDto); _logger.LogInformation( "accelerated registration on chain: {id} result: TransactionId: {transactionId}, BlockNumber: {number}, Status: {status}, ErrorInfo: {error}", @@ -371,10 +380,10 @@ public async Task SocialRecoveryAsync(SocialRecoveryDto so if (result != null) { _logger.LogInformation( - "SocialRecovery to chain: {id} result:" + - "TransactionId: {transactionId}, BlockNumber: {number}, Status: {status}, ErrorInfo: {error}", - socialRecoveryDto.ChainId, - result.TransactionId, result.BlockNumber, result.Status, result.Error); + "SocialRecovery to chain: {id} result:" + + "TransactionId: {transactionId}, BlockNumber: {number}, Status: {status}, ErrorInfo: {error}", + socialRecoveryDto.ChainId, + result.TransactionId, result.BlockNumber, result.Status, result.Error); } return result; @@ -396,8 +405,9 @@ public async Task ValidateTransactionAsync(string chainId, try { await CheckCreateChainIdAsync(result); - - var transactionDto = await _contractServiceProxy.ValidateTransactionAsync(chainId, result, unsetLoginGuardians); + + var transactionDto = + await _contractServiceProxy.ValidateTransactionAsync(chainId, result, unsetLoginGuardians); _logger.LogInformation( "ValidateTransaction to chain: {id} result:" + @@ -576,6 +586,7 @@ public async Task SendTransferRedPacketRefundAsync(RedPackag { return null; } + var grab = redPackageDetail.Items.Sum(item => long.Parse(item.Amount)); var sendInput = new RefundCryptoBoxInput { @@ -585,8 +596,9 @@ public async Task SendTransferRedPacketRefundAsync(RedPackag await redPackageKeyGrain.GenerateSignature( $"{redPackageId}-{long.Parse(redPackageDetail.TotalAmount) - grab}") }; - _logger.LogInformation("SendTransferRedPacketRefundAsync input {input}",JsonConvert.SerializeObject(sendInput)); - + _logger.LogInformation("SendTransferRedPacketRefundAsync input {input}", + JsonConvert.SerializeObject(sendInput)); + return await _contractServiceProxy.SendTransferRedPacketToChainAsync(chainId, sendInput, payRedPackageFrom, chainInfo.RedPackageContractAddress, MethodName.RefundCryptoBox); } @@ -627,7 +639,8 @@ await redPackageKeyGrain.GenerateSignature( CryptoBoxId = redPackageId.ToString(), TransferCryptoBoxInputs = { list } }; - _logger.LogInformation("SendTransferRedPacketToChainAsync sendInput: {sendInput}", JsonConvert.SerializeObject(sendInput)); + _logger.LogInformation("SendTransferRedPacketToChainAsync sendInput: {sendInput}", + JsonConvert.SerializeObject(sendInput)); var contractServiceGrain = _clusterClient.GetGrain(Guid.NewGuid()); return await _contractServiceProxy.SendTransferRedPacketToChainAsync(chainId, sendInput, payRedPackageFrom, diff --git a/src/CAServer.ContractEventHandler.Core/CAServerContractEventHandlerCoreModule.cs b/src/CAServer.ContractEventHandler.Core/CAServerContractEventHandlerCoreModule.cs index 1af628415..377567264 100644 --- a/src/CAServer.ContractEventHandler.Core/CAServerContractEventHandlerCoreModule.cs +++ b/src/CAServer.ContractEventHandler.Core/CAServerContractEventHandlerCoreModule.cs @@ -1,9 +1,13 @@ +using System; +using System.Collections.Generic; +using CAServer.Commons; using CAServer.ContractEventHandler.Core.Application; using CAServer.Grains.Grain.ValidateOriginChainId; using CAServer.Signature; using GraphQL.Client.Abstractions; using GraphQL.Client.Http; using GraphQL.Client.Serializer.Newtonsoft; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Volo.Abp; using Volo.Abp.AutoMapper; diff --git a/src/CAServer.ContractEventHandler/CAServerContractEventHandlerModule.cs b/src/CAServer.ContractEventHandler/CAServerContractEventHandlerModule.cs index ee5f9c9b3..42be53975 100644 --- a/src/CAServer.ContractEventHandler/CAServerContractEventHandlerModule.cs +++ b/src/CAServer.ContractEventHandler/CAServerContractEventHandlerModule.cs @@ -27,6 +27,8 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Microsoft.IdentityModel.Tokens; using MongoDB.Driver; using Orleans; using Orleans.Configuration; @@ -97,6 +99,8 @@ public override void ConfigureServices(ServiceConfigurationContext context) ConfigureDistributedLocking(context, configuration); ConfigureHangfire(context, configuration); // ConfigureOpenTelemetry(context); + + AddAelfClient(context, configuration); } private void ConfigureCache(IConfiguration configuration) @@ -248,4 +252,27 @@ private void ConfigureHangfire(ServiceConfigurationContext context, IConfigurati opt.Queues = new[] { "default", "notDefault" }; }); } + + private void AddAelfClient(ServiceConfigurationContext context, IConfiguration configuration) + { + var chainInfos = context.Services.BuildServiceProvider().GetRequiredService>(); + if (chainInfos == null || chainInfos.Value.ChainInfos.IsNullOrEmpty()) + { + return; + } + + foreach (var chainInfo in chainInfos.Value.ChainInfos) + { + var clientName = chainInfo.Key == CommonConstant.MainChainId + ? AelfClientConstant.MainChainClient + : AelfClientConstant.SideChainClient; + + context.Services.AddHttpClient(clientName, + httpClient => + { + httpClient.BaseAddress = new Uri(chainInfo.Value.BaseUrl); + httpClient.Timeout = TimeSpan.FromSeconds(60); + }); + } + } } \ No newline at end of file diff --git a/src/CAServer.ContractEventHandler/appsettings.json b/src/CAServer.ContractEventHandler/appsettings.json index bf1d73381..e82dbdbad 100644 --- a/src/CAServer.ContractEventHandler/appsettings.json +++ b/src/CAServer.ContractEventHandler/appsettings.json @@ -46,8 +46,8 @@ "PrivateKey": "***", "IsMainChain": true }, - "tDVV": { - "ChainId": "tDVV", + "tDVW": { + "ChainId": "tDVW", "BaseUrl": "http://127.0.0.1:8000", "ContractAddress": "***", "TokenContractAddress": "***", @@ -73,7 +73,7 @@ } }, "GraphQL": { - "GraphQLConnection": "http://127.0.0.1:8083/Indexer_DApp/PortKeyIndexerCASchema/graphql" + "Configuration": "http://127.0.0.1:8083/Indexer_DApp/PortKeyIndexerCASchema/graphql" }, "Sync": { "Sync": 30, From 26daf0d198624f6591505eb8f912a1fdfe3b6d4a Mon Sep 17 00:00:00 2001 From: felix-zhaolei Date: Fri, 20 Dec 2024 18:49:51 +0800 Subject: [PATCH 3/3] modify: swap elephant image. --- .../Tokens/TokenNftAppService.cs | 36 +++++++++++++------ 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/src/CAServer.Application/Tokens/TokenNftAppService.cs b/src/CAServer.Application/Tokens/TokenNftAppService.cs index 4c4e50544..964b3ae7c 100644 --- a/src/CAServer.Application/Tokens/TokenNftAppService.cs +++ b/src/CAServer.Application/Tokens/TokenNftAppService.cs @@ -61,6 +61,7 @@ public class TokenNftAppService : CAServerAppService, ITokenNftAppService private readonly IHttpClientService _httpClientService; private readonly HostInfoOptions _hostInfoOptions; private readonly AwakenOptions _awakenOptions; + private readonly TokenInfoOptions _tokenInfoOptions; public TokenNftAppService( ILogger logger, IUserAssetsProvider userAssetsProvider, @@ -74,7 +75,8 @@ public TokenNftAppService( ISearchAppService searchAppService, IOptionsSnapshot ipfsOption, IOptionsSnapshot tokenListOptions, IOptionsSnapshot nftToFtOptions, IZeroHoldingsConfigAppService zeroHoldingsConfigAppService, IHttpClientService httpClientService, - IOptionsSnapshot hostInfoOptions, IOptionsSnapshot awakenOptions) + IOptionsSnapshot hostInfoOptions, IOptionsSnapshot awakenOptions, + IOptionsSnapshot tokenInfoOptions) { _logger = logger; _userAssetsProvider = userAssetsProvider; @@ -97,6 +99,7 @@ public TokenNftAppService( _httpClientService = httpClientService; _hostInfoOptions = hostInfoOptions.Value; _awakenOptions = awakenOptions.Value; + _tokenInfoOptions = tokenInfoOptions.Value; } public async Task GetTokenAsync(GetTokenRequestDto requestDto) @@ -225,7 +228,7 @@ private async Task DoGetTokenDtos(GetTokenRequestDto requestDto) }); // await filterZeroByConfig(dto); - + return dto; } catch (Exception e) @@ -779,8 +782,9 @@ await _imageProcessProvider.GetResizeImageAsync(searchItem.NftInfo.ImageUrl, req .ThenBy(t => !defaultSymbols.Contains(t.Symbol)) .ThenBy(t => Array.IndexOf(defaultSymbols.ToArray(), t.Symbol)) .ThenBy(t => t.Symbol).ThenByDescending(t => t.ChainId) - .Union(dto.Data.Where(f => f.NftInfo != null).OrderBy(e => e.Symbol).ThenByDescending(t => t.ChainId)).ToList(); - + .Union(dto.Data.Where(f => f.NftInfo != null).OrderBy(e => e.Symbol).ThenByDescending(t => t.ChainId)) + .ToList(); + dto.Data = dto.Data.Skip(requestDto.SkipCount).Take(requestDto.MaxResultCount).ToList(); SetSeedStatusAndTypeForUserAssets(dto.Data); @@ -1003,7 +1007,8 @@ private List SortTokens(List tokens) } catch (Exception e) { - _logger.LogError(e, "illegal tokens:{0}", JsonConvert.SerializeObject(tokens.Where(t => t.Balance.IsNullOrEmpty()).ToList())); + _logger.LogError(e, "illegal tokens:{0}", + JsonConvert.SerializeObject(tokens.Where(t => t.Balance.IsNullOrEmpty()).ToList())); return tokens; } } @@ -1061,8 +1066,9 @@ private List GetTokenInfoList(List userTokenInf return result; } - - public async Task ListAwakenSupportedTokensAsync(int skipCount, int maxResultCount, int page, string chainId, string caAddress) + + public async Task ListAwakenSupportedTokensAsync(int skipCount, int maxResultCount, + int page, string chainId, string caAddress) { if (chainId.IsNullOrEmpty()) { @@ -1070,7 +1076,9 @@ public async Task ListAwakenSupportedTokensAsync(i ? CommonConstant.TDVWChainId : CommonConstant.TDVVChainId; } - var awakenUrl = _awakenOptions.Domain + $"/api/app/trade-pairs?skipCount={skipCount}&maxResultCount={maxResultCount}&page={page}&chainId={chainId}"; + + var awakenUrl = _awakenOptions.Domain + + $"/api/app/trade-pairs?skipCount={skipCount}&maxResultCount={maxResultCount}&page={page}&chainId={chainId}"; var response = await _httpClientService.GetAsync>(awakenUrl); if (!response.Success || response.Data == null || response.Data.Items.IsNullOrEmpty()) { @@ -1087,6 +1095,7 @@ public async Task ListAwakenSupportedTokensAsync(i var tokens = tokens0.Distinct(new TokenComparer()).ToList(); var result = ObjectMapper.Map, List>(tokens); var symbolToToken = await ListSideChainUserTokens(chainId, caAddress, tokens); + var tokenImageDic = _tokenInfoOptions.TokenInfos.ToDictionary(k => k.Key, v => v.Value.ImageUrl); foreach (var token in result) { ChainDisplayNameHelper.SetDisplayName(token); @@ -1094,6 +1103,8 @@ public async Task ListAwakenSupportedTokensAsync(i { token.Balance = token.Balance.IsNullOrEmpty() ? "0" : token.Balance; token.BalanceInUsd = token.BalanceInUsd.IsNullOrEmpty() ? "0" : token.BalanceInUsd; + token.ImageUrl = !token.ImageUrl.IsNullOrEmpty() ? token.ImageUrl : + tokenImageDic.TryGetValue(token.Symbol, out var imageUrl) ? imageUrl : ""; continue; } @@ -1106,6 +1117,7 @@ public async Task ListAwakenSupportedTokensAsync(i token.Price = userToken.Price; token.Label = userToken.Label; } + result = SortTokens(result); result = result.Skip(skipCount).Take(maxResultCount).ToList(); return new AwakenSupportedTokenResponse() @@ -1114,8 +1126,9 @@ public async Task ListAwakenSupportedTokensAsync(i Data = result }; } - - private async Task> ListSideChainUserTokens(string chainId, string caAddress, List tokens) + + private async Task> ListSideChainUserTokens(string chainId, string caAddress, + List tokens) { var userTokens = await DoGetTokenDtos(new GetTokenRequestDto() { @@ -1131,7 +1144,8 @@ private async Task> ListSideChainUserTokens(string cha MaxResultCount = 200 }); var symbols = tokens.Select(t => t.Symbol).Distinct().ToList(); - var sideChainUserTokens = userTokens.Data.Where(t => chainId.Equals(t.ChainId) && symbols.Contains(t.Symbol)).ToList(); + var sideChainUserTokens = + userTokens.Data.Where(t => chainId.Equals(t.ChainId) && symbols.Contains(t.Symbol)).ToList(); try { return sideChainUserTokens.ToDictionary(token => token.Symbol, token => token);