mirror of
https://github.com/JKorf/CryptoExchange.Net.git
synced 2026-08-14 18:02:58 +00:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| fde8d6353b | |||
| 41b996168a | |||
| b26f8fb900 | |||
| bdbbc61d86 | |||
| d64e200f2f |
@@ -0,0 +1,23 @@
|
|||||||
|
name: Publish Nuget
|
||||||
|
|
||||||
|
on:
|
||||||
|
release:
|
||||||
|
types: [published]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 5
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: Setup .NET SDK
|
||||||
|
uses: actions/setup-dotnet@v1
|
||||||
|
- name: Build
|
||||||
|
run: dotnet build -c Release
|
||||||
|
- name: Test
|
||||||
|
run: dotnet test -c Release --no-build
|
||||||
|
- name: Pack nugets
|
||||||
|
run: dotnet pack -c Release --no-build --include-symbols -p:PackageVersion=${{github.event.release.name}} --output .
|
||||||
|
- name: Push Package to NuGet
|
||||||
|
run: dotnet nuget push "*.nupkg" --api-key ${{secrets.nuget_api_key}} --source https://api.nuget.org/v3/index.json
|
||||||
@@ -21,7 +21,7 @@ namespace CryptoExchange.Net.Authentication
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Provided credentials
|
/// Provided credentials
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected readonly ApiCredentials _credentials;
|
protected internal readonly ApiCredentials _credentials;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Byte representation of the secret
|
/// Byte representation of the secret
|
||||||
|
|||||||
@@ -235,7 +235,7 @@ namespace CryptoExchange.Net.Clients
|
|||||||
|
|
||||||
if (ClientOptions.RateLimiterEnabled)
|
if (ClientOptions.RateLimiterEnabled)
|
||||||
{
|
{
|
||||||
var limitResult = await definition.RateLimitGate.ProcessAsync(_logger, requestId, RateLimitItemType.Request, definition, baseAddress, ApiOptions.ApiCredentials?.Key ?? ClientOptions.ApiCredentials?.Key, requestWeight, ClientOptions.RateLimitingBehaviour, cancellationToken).ConfigureAwait(false);
|
var limitResult = await definition.RateLimitGate.ProcessAsync(_logger, requestId, RateLimitItemType.Request, definition, baseAddress, AuthenticationProvider?._credentials.Key, requestWeight, ClientOptions.RateLimitingBehaviour, cancellationToken).ConfigureAwait(false);
|
||||||
if (!limitResult)
|
if (!limitResult)
|
||||||
return new CallResult(limitResult.Error!);
|
return new CallResult(limitResult.Error!);
|
||||||
}
|
}
|
||||||
@@ -249,7 +249,7 @@ namespace CryptoExchange.Net.Clients
|
|||||||
|
|
||||||
if (ClientOptions.RateLimiterEnabled)
|
if (ClientOptions.RateLimiterEnabled)
|
||||||
{
|
{
|
||||||
var limitResult = await definition.RateLimitGate.ProcessSingleAsync(_logger, requestId, RateLimitItemType.Request, definition, baseAddress, ApiOptions.ApiCredentials?.Key ?? ClientOptions.ApiCredentials?.Key, requestWeight, ClientOptions.RateLimitingBehaviour, cancellationToken).ConfigureAwait(false);
|
var limitResult = await definition.RateLimitGate.ProcessSingleAsync(_logger, requestId, RateLimitItemType.Request, definition, baseAddress, AuthenticationProvider?._credentials.Key, requestWeight, ClientOptions.RateLimitingBehaviour, cancellationToken).ConfigureAwait(false);
|
||||||
if (!limitResult)
|
if (!limitResult)
|
||||||
return new CallResult(limitResult.Error!);
|
return new CallResult(limitResult.Error!);
|
||||||
}
|
}
|
||||||
@@ -513,7 +513,7 @@ namespace CryptoExchange.Net.Clients
|
|||||||
|
|
||||||
if (ClientOptions.RateLimiterEnabled)
|
if (ClientOptions.RateLimiterEnabled)
|
||||||
{
|
{
|
||||||
var limitResult = await gate.ProcessAsync(_logger, requestId, RateLimitItemType.Request, new RequestDefinition(uri.AbsolutePath.TrimStart('/'), method) { Authenticated = signed }, uri.Host, ApiOptions.ApiCredentials?.Key ?? ClientOptions.ApiCredentials?.Key, requestWeight, ClientOptions.RateLimitingBehaviour, cancellationToken).ConfigureAwait(false);
|
var limitResult = await gate.ProcessAsync(_logger, requestId, RateLimitItemType.Request, new RequestDefinition(uri.AbsolutePath.TrimStart('/'), method) { Authenticated = signed }, uri.Host, AuthenticationProvider?._credentials.Key, requestWeight, ClientOptions.RateLimitingBehaviour, cancellationToken).ConfigureAwait(false);
|
||||||
if (!limitResult)
|
if (!limitResult)
|
||||||
return new CallResult<IRequest>(limitResult.Error!);
|
return new CallResult<IRequest>(limitResult.Error!);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,9 +6,9 @@
|
|||||||
<PackageId>CryptoExchange.Net</PackageId>
|
<PackageId>CryptoExchange.Net</PackageId>
|
||||||
<Authors>JKorf</Authors>
|
<Authors>JKorf</Authors>
|
||||||
<Description>CryptoExchange.Net is a base library which is used to implement different cryptocurrency (exchange) API's. It provides a standardized way of implementing different API's, which results in a very similar experience for users of the API implementations.</Description>
|
<Description>CryptoExchange.Net is a base library which is used to implement different cryptocurrency (exchange) API's. It provides a standardized way of implementing different API's, which results in a very similar experience for users of the API implementations.</Description>
|
||||||
<PackageVersion>7.5.0</PackageVersion>
|
<PackageVersion>7.5.1</PackageVersion>
|
||||||
<AssemblyVersion>7.5.0</AssemblyVersion>
|
<AssemblyVersion>7.5.1</AssemblyVersion>
|
||||||
<FileVersion>7.5.0</FileVersion>
|
<FileVersion>7.5.1</FileVersion>
|
||||||
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
|
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
|
||||||
<PackageTags>OKX;OKX.Net;Mexc;Mexc.Net;Kucoin;Kucoin.Net;Kraken;Kraken.Net;Huobi;Huobi.Net;CoinEx;CoinEx.Net;Bybit;Bybit.Net;Bitget;Bitget.Net;Bitfinex;Bitfinex.Net;Binance;Binance.Net;CryptoCurrency;CryptoCurrency Exchange</PackageTags>
|
<PackageTags>OKX;OKX.Net;Mexc;Mexc.Net;Kucoin;Kucoin.Net;Kraken;Kraken.Net;Huobi;Huobi.Net;CoinEx;CoinEx.Net;Bybit;Bybit.Net;Bitget;Bitget.Net;Bitfinex;Bitfinex.Net;Binance;Binance.Net;CryptoCurrency;CryptoCurrency Exchange</PackageTags>
|
||||||
<RepositoryType>git</RepositoryType>
|
<RepositoryType>git</RepositoryType>
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using System.Diagnostics;
|
|||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using System.Text.Json.Nodes;
|
||||||
using CryptoExchange.Net.Converters;
|
using CryptoExchange.Net.Converters;
|
||||||
using CryptoExchange.Net.Converters.JsonNet;
|
using CryptoExchange.Net.Converters.JsonNet;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
@@ -257,6 +258,64 @@ namespace CryptoExchange.Net.Testing.Comparers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if(propValue.Type == JTokenType.Array)
|
||||||
|
{
|
||||||
|
var jObjs = (JArray)propValue;
|
||||||
|
if (propertyValue is IEnumerable list)
|
||||||
|
{
|
||||||
|
var enumerator = list.GetEnumerator();
|
||||||
|
foreach (var jObj in jObjs)
|
||||||
|
{
|
||||||
|
enumerator.MoveNext();
|
||||||
|
if (jObj.Type == JTokenType.Object)
|
||||||
|
{
|
||||||
|
foreach (var subProp in ((JObject)jObj).Properties())
|
||||||
|
{
|
||||||
|
if (ignoreProperties?.Contains(subProp.Name) == true)
|
||||||
|
continue;
|
||||||
|
CheckObject(method, subProp, enumerator.Current, ignoreProperties!);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (jObj.Type == JTokenType.Array)
|
||||||
|
{
|
||||||
|
var resultObj = enumerator.Current;
|
||||||
|
var resultProps = resultObj.GetType().GetProperties().Select(p => (p, p.GetCustomAttributes(typeof(ArrayPropertyAttribute), true).Cast<ArrayPropertyAttribute>().SingleOrDefault()));
|
||||||
|
var arrayConverterProperty = resultObj.GetType().GetCustomAttributes(typeof(JsonConverterAttribute), true).FirstOrDefault();
|
||||||
|
var jsonConverter = ((JsonConverterAttribute)arrayConverterProperty!).ConverterType;
|
||||||
|
if (jsonConverter != typeof(ArrayConverter))
|
||||||
|
// Not array converter?
|
||||||
|
continue;
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
foreach (var item in jObj.Values())
|
||||||
|
{
|
||||||
|
var arrayProp = resultProps.SingleOrDefault(p => p.Item2!.Index == i).p;
|
||||||
|
if (arrayProp != null)
|
||||||
|
CheckPropertyValue(method, item, arrayProp.GetValue(resultObj), arrayProp.PropertyType, arrayProp.Name, "Array index " + i, ignoreProperties!);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var value = enumerator.Current;
|
||||||
|
if (value == default && ((JValue)jObj).Type != JTokenType.Null)
|
||||||
|
throw new Exception($"{method}: Array has no value while input json array has value {jObj}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var resultProps = propertyValue.GetType().GetProperties().Select(p => (p, p.GetCustomAttributes(typeof(ArrayPropertyAttribute), true).Cast<ArrayPropertyAttribute>().SingleOrDefault()));
|
||||||
|
int i = 0;
|
||||||
|
foreach (var item in jObjs.Values())
|
||||||
|
{
|
||||||
|
var arrayProp = resultProps.SingleOrDefault(p => p.Item2!.Index == i).p;
|
||||||
|
if (arrayProp != null)
|
||||||
|
CheckPropertyValue(method, item, arrayProp.GetValue(propertyValue), arrayProp.PropertyType, arrayProp.Name, "Array index " + i, ignoreProperties!);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
CheckValues(method, propertyName!, propertyType, (JValue)propValue, propertyValue);
|
CheckValues(method, propertyName!, propertyType, (JValue)propValue, propertyValue);
|
||||||
@@ -278,7 +337,7 @@ namespace CryptoExchange.Net.Testing.Comparers
|
|||||||
if (time != DateTimeConverter.ParseFromString(jsonValue.Value<string>()!))
|
if (time != DateTimeConverter.ParseFromString(jsonValue.Value<string>()!))
|
||||||
throw new Exception($"{method}: {property} not equal: {jsonValue.Value<decimal>()} vs {time}");
|
throw new Exception($"{method}: {property} not equal: {jsonValue.Value<decimal>()} vs {time}");
|
||||||
}
|
}
|
||||||
else if (propertyType.IsEnum)
|
else if (propertyType.IsEnum || Nullable.GetUnderlyingType(propertyType)?.IsEnum == true)
|
||||||
{
|
{
|
||||||
// TODO enum comparing
|
// TODO enum comparing
|
||||||
}
|
}
|
||||||
@@ -305,7 +364,10 @@ namespace CryptoExchange.Net.Testing.Comparers
|
|||||||
}
|
}
|
||||||
else if (jsonValue.Type == JTokenType.Boolean)
|
else if (jsonValue.Type == JTokenType.Boolean)
|
||||||
{
|
{
|
||||||
if (jsonValue.Value<bool>() != (bool)objectValue)
|
if (objectValue is bool boolVal && jsonValue.Value<bool>() != boolVal)
|
||||||
|
throw new Exception($"{method}: {property} not equal: {jsonValue.Value<bool>()} vs {(bool)objectValue}");
|
||||||
|
|
||||||
|
if (jsonValue.Value<bool>() != bool.Parse(objectValue.ToString()))
|
||||||
throw new Exception($"{method}: {property} not equal: {jsonValue.Value<bool>()} vs {(bool)objectValue}");
|
throw new Exception($"{method}: {property} not equal: {jsonValue.Value<bool>()} vs {(bool)objectValue}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ namespace CryptoExchange.Net.Testing.Implementations
|
|||||||
{
|
{
|
||||||
internal class TestRequest : IRequest
|
internal class TestRequest : IRequest
|
||||||
{
|
{
|
||||||
|
private readonly Dictionary<string, IEnumerable<string>> _headers = new Dictionary<string, IEnumerable<string>>();
|
||||||
private readonly TestResponse _response;
|
private readonly TestResponse _response;
|
||||||
|
|
||||||
public string Accept { set { } }
|
public string Accept { set { } }
|
||||||
@@ -31,9 +32,10 @@ namespace CryptoExchange.Net.Testing.Implementations
|
|||||||
|
|
||||||
public void AddHeader(string key, string value)
|
public void AddHeader(string key, string value)
|
||||||
{
|
{
|
||||||
|
_headers.Add(key, new[] { value });
|
||||||
}
|
}
|
||||||
|
|
||||||
public Dictionary<string, IEnumerable<string>> GetHeaders() => new();
|
public Dictionary<string, IEnumerable<string>> GetHeaders() => _headers;
|
||||||
|
|
||||||
public Task<IResponse> GetResponseAsync(CancellationToken cancellationToken) => Task.FromResult<IResponse>(_response);
|
public Task<IResponse> GetResponseAsync(CancellationToken cancellationToken) => Task.FromResult<IResponse>(_response);
|
||||||
|
|
||||||
|
|||||||
@@ -170,8 +170,9 @@ namespace CryptoExchange.Net.Testing
|
|||||||
var expectedMethod = reader.ReadLine();
|
var expectedMethod = reader.ReadLine();
|
||||||
var expectedPath = reader.ReadLine();
|
var expectedPath = reader.ReadLine();
|
||||||
var expectedAuth = bool.Parse(reader.ReadLine()!);
|
var expectedAuth = bool.Parse(reader.ReadLine()!);
|
||||||
|
var response = reader.ReadToEnd();
|
||||||
|
|
||||||
TestHelpers.ConfigureRestClient(_client, "", System.Net.HttpStatusCode.OK);
|
TestHelpers.ConfigureRestClient(_client, response, System.Net.HttpStatusCode.OK);
|
||||||
var result = await methodInvoke(_client).ConfigureAwait(false);
|
var result = await methodInvoke(_client).ConfigureAwait(false);
|
||||||
|
|
||||||
// Check request/response properties
|
// Check request/response properties
|
||||||
|
|||||||
@@ -45,6 +45,9 @@ Make a one time donation in a crypto currency of your choice. If you prefer to d
|
|||||||
Alternatively, sponsor me on Github using [Github Sponsors](https://github.com/sponsors/JKorf).
|
Alternatively, sponsor me on Github using [Github Sponsors](https://github.com/sponsors/JKorf).
|
||||||
|
|
||||||
## Release notes
|
## Release notes
|
||||||
|
* Version 7.5.1 - 03 May 2024
|
||||||
|
* Some small improvements in unit testing components
|
||||||
|
|
||||||
* Version 7.5.0 - 01 May 2024
|
* Version 7.5.0 - 01 May 2024
|
||||||
* Added testing implementations
|
* Added testing implementations
|
||||||
* Small refactor AuthenticationProvider to allow better testing
|
* Small refactor AuthenticationProvider to allow better testing
|
||||||
|
|||||||
Reference in New Issue
Block a user