-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'feature/http-client' into feature/2.7.1-union
- Loading branch information
Showing
9 changed files
with
502 additions
and
8 deletions.
There are no files selected for viewing
7 changes: 7 additions & 0 deletions
7
src/CAServer.Application.Contracts/Commons/AelfClientConstant.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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"; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
28 changes: 28 additions & 0 deletions
28
src/CAServer.Application/Common/AelfClient/IContractClient.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} | ||
|
28 changes: 28 additions & 0 deletions
28
src/CAServer.Application/Common/AelfClient/IContractClientSelector.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
194
src/CAServer.Application/Common/AelfClient/MainChainContractClient.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} |
Oops, something went wrong.