Skip to content

Commit

Permalink
Merge branch 'feature/http-client' into feature/2.7.1-union
Browse files Browse the repository at this point in the history
  • Loading branch information
felix-zhaolei committed Dec 18, 2024
2 parents 03e7ef3 + e9fb0ac commit 510d4c1
Show file tree
Hide file tree
Showing 9 changed files with 502 additions and 8 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace CAServer.Commons;

public static class AelfClientConstant
{
public const string MainChainClient = "MainChainClient";
public const string SideChainClient = "SideChainClient";
}
3 changes: 3 additions & 0 deletions src/CAServer.Application/CAServerApplicationModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -174,6 +175,8 @@ public override void ConfigureServices(ServiceConfigurationContext context)
context.Services.AddScoped<IIpInfoClient, IpInfoClient>();
context.Services.AddScoped<IHttpClientService, HttpClientService>();
context.Services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
context.Services.AddSingleton<IContractClient, MainChainContractClient>();
context.Services.AddSingleton<IContractClient, SideChainContractClient>();

Configure<VariablesOptions>(configuration.GetSection("Variables"));
context.Services.AddScoped<IImRequestProvider, ImRequestProvider>();
Expand Down
28 changes: 28 additions & 0 deletions src/CAServer.Application/Common/AelfClient/IContractClient.cs
Original file line number Diff line number Diff line change
@@ -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<Transaction> GenerateTransactionAsync(
string from,
string to,
string methodName,
IMessage input);

Task<BlockDto> GetBlockByHeightAsync(long blockHeight, bool includeTransactions = false);

Task<SendTransactionOutput> SendTransactionAsync(SendTransactionInput input);

Task<TransactionResultDto> GetTransactionResultAsync(string transactionId);
Task<string> ExecuteTransactionAsync(ExecuteTransactionDto input);

Transaction SignTransaction(string privateKeyHex, Transaction transaction);
}

Original file line number Diff line number Diff line change
@@ -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<IContractClient> _contractClients;

public ContractClientSelector(IEnumerable<IContractClient> 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));
}
}
194 changes: 194 additions & 0 deletions src/CAServer.Application/Common/AelfClient/MainChainContractClient.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
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<MainChainContractClient> _logger;

public MainChainContractClient(IHttpClientFactory httpClientFactory, ILogger<MainChainContractClient> logger)
{
_httpClientFactory = httpClientFactory;
_logger = logger;
}

public async Task<Transaction> 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<byte>(4).ToArray<byte>())
};
}
catch (Exception ex)
{
_logger.LogError(ex, "[ContractClient.GenerateTransactionAsync] error, msg:{0},trace:{1}", ex.Message,
ex.StackTrace ?? "-");
return (Transaction)null;
}
}

public async Task<BlockDto> GetBlockByHeightAsync(long blockHeight, bool includeTransactions = false)
{
var uri = string.Format("api/blockChain/blockByHeight?blockHeight={0}&includeTransactions={1}",
blockHeight, includeTransactions);
return await GetAsync<BlockDto>(uri);
}

public async Task<SendTransactionOutput> SendTransactionAsync(SendTransactionInput input)
{
var uri = "api/blockChain/sendTransaction";
var param = new Dictionary<string, string>()
{
{
"RawTransaction",
input.RawTransaction
}
};
var result = await PostAsync<SendTransactionOutput>(uri, param);
return result;
}

public async Task<TransactionResultDto> GetTransactionResultAsync(string transactionId)
{
var url = "api/blockChain/transactionResult?transactionId=" + transactionId;
var res = await GetAsync<TransactionResultDto>(url);
return res;
}

public async Task<string> ExecuteTransactionAsync(ExecuteTransactionDto input)
{
var url = "api/blockChain/executeTransaction";
var param = new Dictionary<string, string>()
{
{
"RawTransaction",
input.RawTransaction
}
};
var res = await PostAsync(url, param);
return res;
}

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<ChainStatusDto> GetChainStatusAsync()
{
var uri = "api/blockChain/chainStatus";
return await GetAsync<ChainStatusDto>(uri);
}

public async Task<T> GetAsync<T>(string url)
{
_logger.LogInformation("[MainChainContractClient] GetAsync begin:{url}", 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] GetError Response not success, url:{url}, code:{code}, message: {message}",
url, response.StatusCode, content);

throw new UserFriendlyException(content, ((int)response.StatusCode).ToString());
}

_logger.LogInformation("[MainChainContractClient] GetAsync end:{url}", url);
return JsonConvert.DeserializeObject<T>(content);
}

public async Task<T> PostAsync<T>(string url, object paramObj)
{
_logger.LogInformation("[MainChainContractClient] PostAsync<T> begin:{url}", url);
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] 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());
}

_logger.LogInformation("[MainChainContractClient] PostAsync<T> end:{url}", url);
return JsonConvert.DeserializeObject<T>(content);
}

public async Task<string> PostAsync(string url, object paramObj)
{
_logger.LogInformation("[MainChainContractClient] PostAsync<T> begin:{url}", url);
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] 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());
}

_logger.LogInformation("[MainChainContractClient] PostAsync<T> end:{url}", url);
return content;
}

private bool ResponseSuccess(HttpStatusCode statusCode) =>
statusCode is HttpStatusCode.OK or HttpStatusCode.NoContent;
}
Loading

0 comments on commit 510d4c1

Please sign in to comment.