mirror of
https://github.com/JKorf/CryptoExchange.Net.git
synced 2026-08-13 09:23:04 +00:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 73764970b0 | |||
| 9ba29035b2 | |||
| 4c953e2c87 |
@@ -6,9 +6,9 @@
|
|||||||
<PackageId>CryptoExchange.Net.Protobuf</PackageId>
|
<PackageId>CryptoExchange.Net.Protobuf</PackageId>
|
||||||
<Authors>JKorf</Authors>
|
<Authors>JKorf</Authors>
|
||||||
<Description>Protobuf support for CryptoExchange.Net</Description>
|
<Description>Protobuf support for CryptoExchange.Net</Description>
|
||||||
<PackageVersion>9.12.0</PackageVersion>
|
<PackageVersion>9.6.0</PackageVersion>
|
||||||
<AssemblyVersion>9.12.0</AssemblyVersion>
|
<AssemblyVersion>9.6.0</AssemblyVersion>
|
||||||
<FileVersion>9.12.0</FileVersion>
|
<FileVersion>9.6.0</FileVersion>
|
||||||
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
|
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
|
||||||
<PackageTags>CryptoExchange;CryptoExchange.Net</PackageTags>
|
<PackageTags>CryptoExchange;CryptoExchange.Net</PackageTags>
|
||||||
<RepositoryType>git</RepositoryType>
|
<RepositoryType>git</RepositoryType>
|
||||||
@@ -41,7 +41,7 @@
|
|||||||
<DocumentationFile>CryptoExchange.Net.Protobuf.xml</DocumentationFile>
|
<DocumentationFile>CryptoExchange.Net.Protobuf.xml</DocumentationFile>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="CryptoExchange.Net" Version="9.12.0" />
|
<PackageReference Include="CryptoExchange.Net" Version="9.6.0" />
|
||||||
<PackageReference Include="protobuf-net" Version="3.2.56" />
|
<PackageReference Include="protobuf-net" Version="3.2.56" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
@@ -5,27 +5,6 @@
|
|||||||
Protobuf support for CryptoExchange.Net.
|
Protobuf support for CryptoExchange.Net.
|
||||||
|
|
||||||
## Release notes
|
## Release notes
|
||||||
* Version 9.12.0 - 03 Nov 2025
|
|
||||||
* Updated CryptoExchange.Net version to 9.12.0, see https://github.com/JKorf/CryptoExchange.Net/releases/
|
|
||||||
|
|
||||||
* Version 9.11.1 - 30 Oct 2025
|
|
||||||
* Updated CryptoExchange.Net version to 9.11.0, see https://github.com/JKorf/CryptoExchange.Net/releases/
|
|
||||||
|
|
||||||
* Version 9.11.0 - 30 Oct 2025
|
|
||||||
* Updated CryptoExchange.Net version to 9.11.0, see https://github.com/JKorf/CryptoExchange.Net/releases/
|
|
||||||
|
|
||||||
* Version 9.10.0 - 15 Oct 2025
|
|
||||||
* Updated CryptoExchange.Net version to 9.10.0, see https://github.com/JKorf/CryptoExchange.Net/releases/
|
|
||||||
|
|
||||||
* Version 9.9.0 - 06 Oct 2025
|
|
||||||
* Updated CryptoExchange.Net version to 9.9.0, see https://github.com/JKorf/CryptoExchange.Net/releases/
|
|
||||||
|
|
||||||
* Version 9.8.0 - 30 Sep 2025
|
|
||||||
* Updated CryptoExchange.Net version to 9.8.0, see https://github.com/JKorf/CryptoExchange.Net/releases/
|
|
||||||
|
|
||||||
* Version 9.7.0 - 01 Sep 2025
|
|
||||||
* Updated CryptoExchange.Net version to 9.7.0, see https://github.com/JKorf/CryptoExchange.Net/releases/
|
|
||||||
|
|
||||||
* Version 9.6.0 - 25 Aug 2025
|
* Version 9.6.0 - 25 Aug 2025
|
||||||
* Updated CryptoExchange.Net version to 9.6.0
|
* Updated CryptoExchange.Net version to 9.6.0
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ using NUnit.Framework.Legacy;
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@@ -114,7 +113,6 @@ namespace CryptoExchange.Net.UnitTests
|
|||||||
{
|
{
|
||||||
var result = new WebCallResult<TestObjectResult>(
|
var result = new WebCallResult<TestObjectResult>(
|
||||||
System.Net.HttpStatusCode.OK,
|
System.Net.HttpStatusCode.OK,
|
||||||
HttpVersion.Version11,
|
|
||||||
new KeyValuePair<string, string[]>[0],
|
new KeyValuePair<string, string[]>[0],
|
||||||
TimeSpan.FromSeconds(1),
|
TimeSpan.FromSeconds(1),
|
||||||
null,
|
null,
|
||||||
@@ -145,7 +143,6 @@ namespace CryptoExchange.Net.UnitTests
|
|||||||
{
|
{
|
||||||
var result = new WebCallResult<TestObjectResult>(
|
var result = new WebCallResult<TestObjectResult>(
|
||||||
System.Net.HttpStatusCode.OK,
|
System.Net.HttpStatusCode.OK,
|
||||||
HttpVersion.Version11,
|
|
||||||
new KeyValuePair<string, string[]>[0],
|
new KeyValuePair<string, string[]>[0],
|
||||||
TimeSpan.FromSeconds(1),
|
TimeSpan.FromSeconds(1),
|
||||||
null,
|
null,
|
||||||
|
|||||||
@@ -6,10 +6,14 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.0"></PackageReference>
|
<None Include="..\CryptoExchange.Net\.editorconfig" Link=".editorconfig" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1"></PackageReference>
|
||||||
<PackageReference Include="Moq" Version="4.20.72" />
|
<PackageReference Include="Moq" Version="4.20.72" />
|
||||||
<PackageReference Include="NUnit" Version="4.4.0"></PackageReference>
|
<PackageReference Include="NUnit" Version="4.3.2"></PackageReference>
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="5.2.0"></PackageReference>
|
<PackageReference Include="NUnit3TestAdapter" Version="5.0.0"></PackageReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -32,7 +32,6 @@ namespace CryptoExchange.Net.UnitTests
|
|||||||
[TestCase(0.1, 1, 0.0001, RoundingType.Closest, 0.532, 0.532)]
|
[TestCase(0.1, 1, 0.0001, RoundingType.Closest, 0.532, 0.532)]
|
||||||
[TestCase(0.1, 1, 0.0001, RoundingType.Down, 0.5516592, 0.5516)]
|
[TestCase(0.1, 1, 0.0001, RoundingType.Down, 0.5516592, 0.5516)]
|
||||||
[TestCase(0.1, 1, 0.0001, RoundingType.Closest, 0.5516592, 0.5517)]
|
[TestCase(0.1, 1, 0.0001, RoundingType.Closest, 0.5516592, 0.5517)]
|
||||||
[TestCase(0, 1, 0.000000001, RoundingType.Closest, 0.0000097232, 0.000009723)]
|
|
||||||
public void AdjustValueStepTests(decimal min, decimal max, decimal? step, RoundingType roundingType, decimal input, decimal expected)
|
public void AdjustValueStepTests(decimal min, decimal max, decimal? step, RoundingType roundingType, decimal input, decimal expected)
|
||||||
{
|
{
|
||||||
var result = ExchangeHelpers.AdjustValueStep(min, max, step, roundingType, input);
|
var result = ExchangeHelpers.AdjustValueStep(min, max, step, roundingType, input);
|
||||||
|
|||||||
@@ -202,7 +202,7 @@ namespace CryptoExchange.Net.UnitTests
|
|||||||
await sub;
|
await sub;
|
||||||
|
|
||||||
// assert
|
// assert
|
||||||
ClassicAssert.IsTrue(client.SubClient.TestSubscription.Status != SubscriptionStatus.Subscribed);
|
ClassicAssert.IsFalse(client.SubClient.TestSubscription.Confirmed);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestCase()]
|
[TestCase()]
|
||||||
@@ -225,7 +225,7 @@ namespace CryptoExchange.Net.UnitTests
|
|||||||
await sub;
|
await sub;
|
||||||
|
|
||||||
// assert
|
// assert
|
||||||
Assert.That(client.SubClient.TestSubscription.Status == SubscriptionStatus.Subscribed);
|
Assert.That(client.SubClient.TestSubscription.Confirmed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,8 +60,8 @@ namespace CryptoExchange.Net.UnitTests.TestImplementations
|
|||||||
request.Setup(c => c.GetHeaders()).Returns(() => headers.ToArray());
|
request.Setup(c => c.GetHeaders()).Returns(() => headers.ToArray());
|
||||||
|
|
||||||
var factory = Mock.Get(Api1.RequestFactory);
|
var factory = Mock.Get(Api1.RequestFactory);
|
||||||
factory.Setup(c => c.Create(It.IsAny<Version>(), It.IsAny<HttpMethod>(), It.IsAny<Uri>(), It.IsAny<int>()))
|
factory.Setup(c => c.Create(It.IsAny<HttpMethod>(), It.IsAny<Uri>(), It.IsAny<int>()))
|
||||||
.Callback<Version, HttpMethod, Uri, int>((version, method, uri, id) =>
|
.Callback<HttpMethod, Uri, int>((method, uri, id) =>
|
||||||
{
|
{
|
||||||
request.Setup(a => a.Uri).Returns(uri);
|
request.Setup(a => a.Uri).Returns(uri);
|
||||||
request.Setup(a => a.Method).Returns(method);
|
request.Setup(a => a.Method).Returns(method);
|
||||||
@@ -69,8 +69,8 @@ namespace CryptoExchange.Net.UnitTests.TestImplementations
|
|||||||
.Returns(request.Object);
|
.Returns(request.Object);
|
||||||
|
|
||||||
factory = Mock.Get(Api2.RequestFactory);
|
factory = Mock.Get(Api2.RequestFactory);
|
||||||
factory.Setup(c => c.Create(It.IsAny<Version>(), It.IsAny<HttpMethod>(), It.IsAny<Uri>(), It.IsAny<int>()))
|
factory.Setup(c => c.Create(It.IsAny<HttpMethod>(), It.IsAny<Uri>(), It.IsAny<int>()))
|
||||||
.Callback<Version, HttpMethod, Uri, int>((version, method, uri, id) =>
|
.Callback<HttpMethod, Uri, int>((method, uri, id) =>
|
||||||
{
|
{
|
||||||
request.Setup(a => a.Uri).Returns(uri);
|
request.Setup(a => a.Uri).Returns(uri);
|
||||||
request.Setup(a => a.Method).Returns(method);
|
request.Setup(a => a.Method).Returns(method);
|
||||||
@@ -90,12 +90,12 @@ namespace CryptoExchange.Net.UnitTests.TestImplementations
|
|||||||
request.Setup(c => c.GetResponseAsync(It.IsAny<CancellationToken>())).Throws(we);
|
request.Setup(c => c.GetResponseAsync(It.IsAny<CancellationToken>())).Throws(we);
|
||||||
|
|
||||||
var factory = Mock.Get(Api1.RequestFactory);
|
var factory = Mock.Get(Api1.RequestFactory);
|
||||||
factory.Setup(c => c.Create(It.IsAny<Version>(), It.IsAny<HttpMethod>(), It.IsAny<Uri>(), It.IsAny<int>()))
|
factory.Setup(c => c.Create(It.IsAny<HttpMethod>(), It.IsAny<Uri>(), It.IsAny<int>()))
|
||||||
.Returns(request.Object);
|
.Returns(request.Object);
|
||||||
|
|
||||||
|
|
||||||
factory = Mock.Get(Api2.RequestFactory);
|
factory = Mock.Get(Api2.RequestFactory);
|
||||||
factory.Setup(c => c.Create(It.IsAny<Version>(), It.IsAny<HttpMethod>(), It.IsAny<Uri>(), It.IsAny<int>()))
|
factory.Setup(c => c.Create(It.IsAny<HttpMethod>(), It.IsAny<Uri>(), It.IsAny<int>()))
|
||||||
.Returns(request.Object);
|
.Returns(request.Object);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,13 +118,13 @@ namespace CryptoExchange.Net.UnitTests.TestImplementations
|
|||||||
request.Setup(c => c.GetHeaders()).Returns(headers.ToArray());
|
request.Setup(c => c.GetHeaders()).Returns(headers.ToArray());
|
||||||
|
|
||||||
var factory = Mock.Get(Api1.RequestFactory);
|
var factory = Mock.Get(Api1.RequestFactory);
|
||||||
factory.Setup(c => c.Create(It.IsAny<Version>(), It.IsAny<HttpMethod>(), It.IsAny<Uri>(), It.IsAny<int>()))
|
factory.Setup(c => c.Create(It.IsAny<HttpMethod>(), It.IsAny<Uri>(), It.IsAny<int>()))
|
||||||
.Callback<Version, HttpMethod, Uri, int>((version, method, uri, id) => request.Setup(a => a.Uri).Returns(uri))
|
.Callback<HttpMethod, Uri, int>((method, uri, id) => request.Setup(a => a.Uri).Returns(uri))
|
||||||
.Returns(request.Object);
|
.Returns(request.Object);
|
||||||
|
|
||||||
factory = Mock.Get(Api2.RequestFactory);
|
factory = Mock.Get(Api2.RequestFactory);
|
||||||
factory.Setup(c => c.Create(It.IsAny<Version>(), It.IsAny<HttpMethod>(), It.IsAny<Uri>(), It.IsAny<int>()))
|
factory.Setup(c => c.Create(It.IsAny<HttpMethod>(), It.IsAny<Uri>(), It.IsAny<int>()))
|
||||||
.Callback<Version, HttpMethod, Uri, int>((version, method, uri, id) => request.Setup(a => a.Uri).Returns(uri))
|
.Callback<HttpMethod, Uri, int>((method, uri, id) => request.Setup(a => a.Uri).Returns(uri))
|
||||||
.Returns(request.Object);
|
.Returns(request.Object);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,132 +0,0 @@
|
|||||||
//using System;
|
|
||||||
//using System.IO;
|
|
||||||
//using System.Net.WebSockets;
|
|
||||||
//using System.Security.Authentication;
|
|
||||||
//using System.Text;
|
|
||||||
//using System.Threading.Tasks;
|
|
||||||
//using CryptoExchange.Net.Interfaces;
|
|
||||||
//using CryptoExchange.Net.Objects;
|
|
||||||
|
|
||||||
//namespace CryptoExchange.Net.UnitTests.TestImplementations
|
|
||||||
//{
|
|
||||||
// public class TestSocket: IWebsocket
|
|
||||||
// {
|
|
||||||
// public bool CanConnect { get; set; }
|
|
||||||
// public bool Connected { get; set; }
|
|
||||||
|
|
||||||
// public event Func<Task> OnClose;
|
|
||||||
//#pragma warning disable 0067
|
|
||||||
// public event Func<Task> OnReconnected;
|
|
||||||
// public event Func<Task> OnReconnecting;
|
|
||||||
// public event Func<int, Task> OnRequestRateLimited;
|
|
||||||
//#pragma warning restore 0067
|
|
||||||
// public event Func<int, Task> OnRequestSent;
|
|
||||||
// public event Func<WebSocketMessageType, ReadOnlyMemory<byte>, Task> OnStreamMessage;
|
|
||||||
// public event Func<Exception, Task> OnError;
|
|
||||||
// public event Func<Task> OnOpen;
|
|
||||||
// public Func<Task<Uri>> GetReconnectionUrl { get; set; }
|
|
||||||
|
|
||||||
// public int Id { get; }
|
|
||||||
// public bool ShouldReconnect { get; set; }
|
|
||||||
// public TimeSpan Timeout { get; set; }
|
|
||||||
// public Func<string, string> DataInterpreterString { get; set; }
|
|
||||||
// public Func<byte[], string> DataInterpreterBytes { get; set; }
|
|
||||||
// public DateTime? DisconnectTime { get; set; }
|
|
||||||
// public string Url { get; }
|
|
||||||
// public bool IsClosed => !Connected;
|
|
||||||
// public bool IsOpen => Connected;
|
|
||||||
// public bool PingConnection { get; set; }
|
|
||||||
// public TimeSpan PingInterval { get; set; }
|
|
||||||
// public SslProtocols SSLProtocols { get; set; }
|
|
||||||
// public Encoding Encoding { get; set; }
|
|
||||||
|
|
||||||
// public int ConnectCalls { get; private set; }
|
|
||||||
// public bool Reconnecting { get; set; }
|
|
||||||
// public string Origin { get; set; }
|
|
||||||
// public int? RatelimitPerSecond { get; set; }
|
|
||||||
|
|
||||||
// public double IncomingKbps => throw new NotImplementedException();
|
|
||||||
|
|
||||||
// public Uri Uri => new Uri("");
|
|
||||||
|
|
||||||
// public TimeSpan KeepAliveInterval { get; set; }
|
|
||||||
|
|
||||||
// public static int lastId = 0;
|
|
||||||
// public static object lastIdLock = new object();
|
|
||||||
|
|
||||||
// public TestSocket()
|
|
||||||
// {
|
|
||||||
// lock (lastIdLock)
|
|
||||||
// {
|
|
||||||
// Id = lastId + 1;
|
|
||||||
// lastId++;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// public Task<CallResult> ConnectAsync()
|
|
||||||
// {
|
|
||||||
// Connected = CanConnect;
|
|
||||||
// ConnectCalls++;
|
|
||||||
// if (CanConnect)
|
|
||||||
// InvokeOpen();
|
|
||||||
// return Task.FromResult(CanConnect ? new CallResult(null) : new CallResult(new CantConnectError()));
|
|
||||||
// }
|
|
||||||
|
|
||||||
// public bool Send(int requestId, string data, int weight)
|
|
||||||
// {
|
|
||||||
// if(!Connected)
|
|
||||||
// throw new Exception("Socket not connected");
|
|
||||||
// OnRequestSent?.Invoke(requestId);
|
|
||||||
// return true;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// public void Reset()
|
|
||||||
// {
|
|
||||||
// }
|
|
||||||
|
|
||||||
// public Task CloseAsync()
|
|
||||||
// {
|
|
||||||
// Connected = false;
|
|
||||||
// DisconnectTime = DateTime.UtcNow;
|
|
||||||
// OnClose?.Invoke();
|
|
||||||
// return Task.FromResult(0);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// public void SetProxy(string host, int port)
|
|
||||||
// {
|
|
||||||
// throw new NotImplementedException();
|
|
||||||
// }
|
|
||||||
// public void Dispose()
|
|
||||||
// {
|
|
||||||
// }
|
|
||||||
|
|
||||||
// public void InvokeClose()
|
|
||||||
// {
|
|
||||||
// Connected = false;
|
|
||||||
// DisconnectTime = DateTime.UtcNow;
|
|
||||||
// Reconnecting = true;
|
|
||||||
// OnClose?.Invoke();
|
|
||||||
// }
|
|
||||||
|
|
||||||
// public void InvokeOpen()
|
|
||||||
// {
|
|
||||||
// OnOpen?.Invoke();
|
|
||||||
// }
|
|
||||||
|
|
||||||
// public void InvokeMessage(string data)
|
|
||||||
// {
|
|
||||||
// OnStreamMessage?.Invoke(WebSocketMessageType.Text, new ReadOnlyMemory<byte>(Encoding.UTF8.GetBytes(data))).Wait();
|
|
||||||
// }
|
|
||||||
|
|
||||||
// public void SetProxy(ApiProxy proxy)
|
|
||||||
// {
|
|
||||||
// throw new NotImplementedException();
|
|
||||||
// }
|
|
||||||
|
|
||||||
// public void InvokeError(Exception error)
|
|
||||||
// {
|
|
||||||
// OnError?.Invoke(error);
|
|
||||||
// }
|
|
||||||
// public Task ReconnectAsync() => Task.CompletedTask;
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
@@ -0,0 +1,183 @@
|
|||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
|
||||||
|
# Indentation and spacing
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
charset = utf-8
|
||||||
|
max_line_length = 140
|
||||||
|
insert_final_newline = true
|
||||||
|
|
||||||
|
# ReSharper code style properties
|
||||||
|
resharper_csharp_keep_existing_embedded_arrangement = false
|
||||||
|
resharper_csharp_place_accessorholder_attribute_on_same_line = false
|
||||||
|
resharper_csharp_wrap_after_declaration_lpar = true
|
||||||
|
resharper_csharp_wrap_parameters_style = chop_if_long
|
||||||
|
resharper_csharp_blank_lines_around_single_line_auto_property = 1
|
||||||
|
resharper_csharp_keep_blank_lines_in_declarations = 1
|
||||||
|
resharper_trailing_comma_in_multiline_lists = true
|
||||||
|
|
||||||
|
[*.cs]
|
||||||
|
|
||||||
|
indent_size = 4
|
||||||
|
|
||||||
|
# Code style conventions
|
||||||
|
dotnet_style_predefined_type_for_member_access = true:suggestion
|
||||||
|
dotnet_style_collection_initializer = true:suggestion
|
||||||
|
dotnet_style_object_initializer = true:suggestion
|
||||||
|
csharp_style_var_when_type_is_apparent = true:suggestion
|
||||||
|
csharp_style_expression_bodied_methods = true:suggestion
|
||||||
|
csharp_style_namespace_declarations = file_scoped:warning
|
||||||
|
dotnet_style_coalesce_expression = true:suggestion
|
||||||
|
dotnet_style_null_propagation = true:suggestion
|
||||||
|
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion
|
||||||
|
dotnet_style_prefer_simplified_boolean_expressions = true:suggestion
|
||||||
|
csharp_prefer_braces = when_multiline:warning
|
||||||
|
|
||||||
|
# Analyzer preferences
|
||||||
|
dotnet_diagnostic.CA2007.severity = warning # Call ConfigureAwait on the awaited Task.
|
||||||
|
dotnet_code_quality.CA2007.exclude_async_void_methods = true
|
||||||
|
dotnet_code_quality.CA2007.output_kind = DynamicallyLinkedLibrary
|
||||||
|
|
||||||
|
dotnet_diagnostic.CA1000.severity = none # Do not declare static members on generic types
|
||||||
|
dotnet_diagnostic.CA1051.severity = none # Do not declare visible instance fields
|
||||||
|
dotnet_diagnostic.CA1510.severity = none # Use ArgumentNullException throw helper
|
||||||
|
dotnet_diagnostic.CA1720.severity = none # Identifiers should not contain type names
|
||||||
|
dotnet_diagnostic.CA1716.severity = none # Identifiers should not match keywords
|
||||||
|
dotnet_diagnostic.CA1835.severity = none # Use ArgumentNullException throw helper
|
||||||
|
dotnet_diagnostic.CA1846.severity = none # Prefer AsSpan over Substring
|
||||||
|
dotnet_diagnostic.CA1848.severity = none # Use the LoggerMessage delegates
|
||||||
|
dotnet_diagnostic.CA1850.severity = none # Prefer static HashData method over ComputeHash
|
||||||
|
dotnet_diagnostic.CA1866.severity = none # Use 'string.Method(char)' instead of 'string.Method(string)' for string with single char
|
||||||
|
dotnet_diagnostic.CA2201.severity = none # Do not raise reserved exception types
|
||||||
|
dotnet_diagnostic.CA2208.severity = none # Do not raise reserved exception types
|
||||||
|
dotnet_diagnostic.IDE0005.severity = warning # Using directive is unnecessary
|
||||||
|
|
||||||
|
[*.xml]
|
||||||
|
ij_xml_space_inside_empty_tag = true
|
||||||
|
[*.cs]
|
||||||
|
#### Naming styles ####
|
||||||
|
|
||||||
|
# Naming rules
|
||||||
|
|
||||||
|
dotnet_naming_rule.interface_should_be_begins_with_i.severity = warning
|
||||||
|
dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface
|
||||||
|
dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i
|
||||||
|
|
||||||
|
dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = warning
|
||||||
|
dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members
|
||||||
|
dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case
|
||||||
|
|
||||||
|
dotnet_naming_rule.private_or_internal_field_should_be_fields_start_with__.severity = warning
|
||||||
|
dotnet_naming_rule.private_or_internal_field_should_be_fields_start_with__.symbols = private_or_internal_field
|
||||||
|
dotnet_naming_rule.private_or_internal_field_should_be_fields_start_with__.style = fields_start_with__
|
||||||
|
|
||||||
|
# Symbol specifications
|
||||||
|
|
||||||
|
dotnet_naming_symbols.interface.applicable_kinds = interface
|
||||||
|
dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
||||||
|
dotnet_naming_symbols.interface.required_modifiers =
|
||||||
|
|
||||||
|
dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
|
||||||
|
dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
||||||
|
dotnet_naming_symbols.non_field_members.required_modifiers =
|
||||||
|
|
||||||
|
dotnet_naming_symbols.private_or_internal_field.applicable_kinds = field
|
||||||
|
dotnet_naming_symbols.private_or_internal_field.applicable_accessibilities = internal, private, private_protected
|
||||||
|
dotnet_naming_symbols.private_or_internal_field.required_modifiers =
|
||||||
|
|
||||||
|
# Naming styles
|
||||||
|
|
||||||
|
dotnet_naming_style.begins_with_i.required_prefix = I
|
||||||
|
dotnet_naming_style.begins_with_i.required_suffix =
|
||||||
|
dotnet_naming_style.begins_with_i.word_separator =
|
||||||
|
dotnet_naming_style.begins_with_i.capitalization = pascal_case
|
||||||
|
|
||||||
|
dotnet_naming_style.pascal_case.required_prefix =
|
||||||
|
dotnet_naming_style.pascal_case.required_suffix =
|
||||||
|
dotnet_naming_style.pascal_case.word_separator =
|
||||||
|
dotnet_naming_style.pascal_case.capitalization = pascal_case
|
||||||
|
|
||||||
|
dotnet_naming_style.fields_start_with__.required_prefix = _
|
||||||
|
dotnet_naming_style.fields_start_with__.required_suffix =
|
||||||
|
dotnet_naming_style.fields_start_with__.word_separator =
|
||||||
|
dotnet_naming_style.fields_start_with__.capitalization = camel_case
|
||||||
|
csharp_indent_labels = one_less_than_current
|
||||||
|
csharp_using_directive_placement = outside_namespace:suggestion
|
||||||
|
csharp_prefer_simple_using_statement = true:suggestion
|
||||||
|
csharp_style_prefer_method_group_conversion = true:silent
|
||||||
|
csharp_style_prefer_top_level_statements = true:silent
|
||||||
|
csharp_style_prefer_primary_constructors = true:suggestion
|
||||||
|
csharp_prefer_system_threading_lock = true:suggestion
|
||||||
|
csharp_style_expression_bodied_constructors = false:silent
|
||||||
|
csharp_style_expression_bodied_operators = false:silent
|
||||||
|
csharp_style_expression_bodied_properties = true:suggestion
|
||||||
|
csharp_style_expression_bodied_indexers = true:suggestion
|
||||||
|
csharp_style_expression_bodied_accessors = true:suggestion
|
||||||
|
csharp_style_expression_bodied_lambdas = true:silent
|
||||||
|
csharp_style_expression_bodied_local_functions = true:silent
|
||||||
|
|
||||||
|
[*.vb]
|
||||||
|
#### Naming styles ####
|
||||||
|
|
||||||
|
# Naming rules
|
||||||
|
|
||||||
|
dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion
|
||||||
|
dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface
|
||||||
|
dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i
|
||||||
|
|
||||||
|
dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion
|
||||||
|
dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members
|
||||||
|
dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case
|
||||||
|
|
||||||
|
# Symbol specifications
|
||||||
|
|
||||||
|
dotnet_naming_symbols.interface.applicable_kinds = interface
|
||||||
|
dotnet_naming_symbols.interface.applicable_accessibilities = public, friend, private, protected, protected_friend, private_protected
|
||||||
|
dotnet_naming_symbols.interface.required_modifiers =
|
||||||
|
|
||||||
|
dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
|
||||||
|
dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, friend, private, protected, protected_friend, private_protected
|
||||||
|
dotnet_naming_symbols.non_field_members.required_modifiers =
|
||||||
|
|
||||||
|
# Naming styles
|
||||||
|
|
||||||
|
dotnet_naming_style.begins_with_i.required_prefix = I
|
||||||
|
dotnet_naming_style.begins_with_i.required_suffix =
|
||||||
|
dotnet_naming_style.begins_with_i.word_separator =
|
||||||
|
dotnet_naming_style.begins_with_i.capitalization = pascal_case
|
||||||
|
|
||||||
|
dotnet_naming_style.pascal_case.required_prefix =
|
||||||
|
dotnet_naming_style.pascal_case.required_suffix =
|
||||||
|
dotnet_naming_style.pascal_case.word_separator =
|
||||||
|
dotnet_naming_style.pascal_case.capitalization = pascal_case
|
||||||
|
|
||||||
|
[*.{cs,vb}]
|
||||||
|
#### Naming styles ####
|
||||||
|
|
||||||
|
# Naming rules
|
||||||
|
|
||||||
|
dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion
|
||||||
|
dotnet_naming_rule.types_should_be_pascal_case.symbols = types
|
||||||
|
dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case
|
||||||
|
|
||||||
|
# Symbol specifications
|
||||||
|
|
||||||
|
dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum
|
||||||
|
dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
||||||
|
dotnet_naming_symbols.types.required_modifiers =
|
||||||
|
|
||||||
|
# Naming styles
|
||||||
|
|
||||||
|
dotnet_naming_style.pascal_case.required_prefix =
|
||||||
|
dotnet_naming_style.pascal_case.required_suffix =
|
||||||
|
dotnet_naming_style.pascal_case.word_separator =
|
||||||
|
dotnet_naming_style.pascal_case.capitalization = pascal_case
|
||||||
|
dotnet_style_operator_placement_when_wrapping = beginning_of_line
|
||||||
|
tab_width = 4
|
||||||
|
end_of_line = crlf
|
||||||
|
dotnet_style_coalesce_expression = true:suggestion
|
||||||
|
dotnet_style_null_propagation = true:suggestion
|
||||||
|
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("CryptoExchange.Net.UnitTests")]
|
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("CryptoExchange.Net.UnitTests")]
|
||||||
|
|
||||||
namespace System.Runtime.CompilerServices
|
namespace System.Runtime.CompilerServices;
|
||||||
{
|
|
||||||
internal static class IsExternalInit { }
|
internal static class IsExternalInit { }
|
||||||
}
|
|
||||||
@@ -1,12 +1,11 @@
|
|||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Attributes
|
namespace CryptoExchange.Net.Attributes;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Used for conversion in ArrayConverter
|
||||||
|
/// </summary>
|
||||||
|
[AttributeUsage(AttributeTargets.Property)]
|
||||||
|
public class JsonConversionAttribute: Attribute
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Used for conversion in ArrayConverter
|
|
||||||
/// </summary>
|
|
||||||
[AttributeUsage(AttributeTargets.Property)]
|
|
||||||
public class JsonConversionAttribute: Attribute
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Attributes
|
namespace CryptoExchange.Net.Attributes;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Map a enum entry to string values
|
||||||
|
/// </summary>
|
||||||
|
[AttributeUsage(AttributeTargets.Field)]
|
||||||
|
public class MapAttribute : Attribute
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Map a enum entry to string values
|
|
||||||
/// </summary>
|
|
||||||
[AttributeUsage(AttributeTargets.Field)]
|
|
||||||
public class MapAttribute : Attribute
|
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Values mapping to the enum entry
|
/// Values mapping to the enum entry
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -21,5 +21,4 @@ namespace CryptoExchange.Net.Attributes
|
|||||||
{
|
{
|
||||||
Values = maps;
|
Values = maps;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,12 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
|
||||||
using CryptoExchange.Net.Converters.SystemTextJson;
|
|
||||||
using CryptoExchange.Net.Converters.MessageParsing;
|
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Authentication
|
namespace CryptoExchange.Net.Authentication;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Api credentials, used to sign requests accessing private endpoints
|
||||||
|
/// </summary>
|
||||||
|
public class ApiCredentials
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Api credentials, used to sign requests accessing private endpoints
|
|
||||||
/// </summary>
|
|
||||||
public class ApiCredentials
|
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The api key / label to authenticate requests
|
/// The api key / label to authenticate requests
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -56,5 +53,4 @@ namespace CryptoExchange.Net.Authentication
|
|||||||
{
|
{
|
||||||
return new ApiCredentials(Key, Secret, Pass, CredentialType);
|
return new ApiCredentials(Key, Secret, Pass, CredentialType);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
namespace CryptoExchange.Net.Authentication
|
namespace CryptoExchange.Net.Authentication;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Credentials type
|
||||||
|
/// </summary>
|
||||||
|
public enum ApiCredentialsType
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Credentials type
|
|
||||||
/// </summary>
|
|
||||||
public enum ApiCredentialsType
|
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Hmac keys credentials
|
/// Hmac keys credentials
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -17,5 +17,4 @@
|
|||||||
/// Rsa keys credentials in pem/base64 format. Only available for .NetStandard 2.1 and up, use xml format for lower.
|
/// Rsa keys credentials in pem/base64 format. Only available for .NetStandard 2.1 and up, use xml format for lower.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
RsaPem
|
RsaPem
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,20 @@
|
|||||||
using CryptoExchange.Net.Clients;
|
using CryptoExchange.Net.Clients;
|
||||||
using CryptoExchange.Net.Converters.SystemTextJson;
|
using CryptoExchange.Net.Converters.SystemTextJson;
|
||||||
using CryptoExchange.Net.Interfaces;
|
using CryptoExchange.Net.Interfaces;
|
||||||
using CryptoExchange.Net.Objects;
|
using CryptoExchange.Net.Objects;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Net.Http;
|
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Authentication
|
namespace CryptoExchange.Net.Authentication;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Base class for authentication providers
|
||||||
|
/// </summary>
|
||||||
|
public abstract class AuthenticationProvider
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Base class for authentication providers
|
|
||||||
/// </summary>
|
|
||||||
public abstract class AuthenticationProvider
|
|
||||||
{
|
|
||||||
internal IAuthTimeProvider TimeProvider { get; set; } = new AuthTimeProvider();
|
internal IAuthTimeProvider TimeProvider { get; set; } = new AuthTimeProvider();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -209,7 +208,9 @@ namespace CryptoExchange.Net.Authentication
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
protected static string SignMD5(string data, SignOutputType? outputType = null)
|
protected static string SignMD5(string data, SignOutputType? outputType = null)
|
||||||
{
|
{
|
||||||
|
#pragma warning disable CA5351
|
||||||
using var encryptor = MD5.Create();
|
using var encryptor = MD5.Create();
|
||||||
|
#pragma warning restore CA5351
|
||||||
var resultBytes = encryptor.ComputeHash(Encoding.UTF8.GetBytes(data));
|
var resultBytes = encryptor.ComputeHash(Encoding.UTF8.GetBytes(data));
|
||||||
return outputType == SignOutputType.Base64 ? BytesToBase64String(resultBytes) : BytesToHexString(resultBytes);
|
return outputType == SignOutputType.Base64 ? BytesToBase64String(resultBytes) : BytesToHexString(resultBytes);
|
||||||
}
|
}
|
||||||
@@ -222,7 +223,9 @@ namespace CryptoExchange.Net.Authentication
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
protected static string SignMD5(byte[] data, SignOutputType? outputType = null)
|
protected static string SignMD5(byte[] data, SignOutputType? outputType = null)
|
||||||
{
|
{
|
||||||
|
#pragma warning disable CA5351
|
||||||
using var encryptor = MD5.Create();
|
using var encryptor = MD5.Create();
|
||||||
|
#pragma warning restore CA5351
|
||||||
var resultBytes = encryptor.ComputeHash(data);
|
var resultBytes = encryptor.ComputeHash(data);
|
||||||
return outputType == SignOutputType.Base64 ? BytesToBase64String(resultBytes) : BytesToHexString(resultBytes);
|
return outputType == SignOutputType.Base64 ? BytesToBase64String(resultBytes) : BytesToHexString(resultBytes);
|
||||||
}
|
}
|
||||||
@@ -234,7 +237,9 @@ namespace CryptoExchange.Net.Authentication
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
protected static byte[] SignMD5Bytes(string data)
|
protected static byte[] SignMD5Bytes(string data)
|
||||||
{
|
{
|
||||||
|
#pragma warning disable CA5351
|
||||||
using var encryptor = MD5.Create();
|
using var encryptor = MD5.Create();
|
||||||
|
#pragma warning restore CA5351
|
||||||
return encryptor.ComputeHash(Encoding.UTF8.GetBytes(data));
|
return encryptor.ComputeHash(Encoding.UTF8.GetBytes(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -454,13 +459,17 @@ namespace CryptoExchange.Net.Authentication
|
|||||||
else
|
else
|
||||||
return stringSerializer.Serialize(parameters);
|
return stringSerializer.Serialize(parameters);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public abstract class AuthenticationProvider<TApiCredentials> : AuthenticationProvider where TApiCredentials : ApiCredentials
|
||||||
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public abstract class AuthenticationProvider<TApiCredentials> : AuthenticationProvider where TApiCredentials : ApiCredentials
|
#pragma warning disable IDE1006 // Naming Styles
|
||||||
{
|
#pragma warning disable CA1707 // Naming Styles
|
||||||
/// <inheritdoc />
|
|
||||||
protected new TApiCredentials _credentials => (TApiCredentials)base._credentials;
|
protected new TApiCredentials _credentials => (TApiCredentials)base._credentials;
|
||||||
|
#pragma warning restore IDE1006 // Naming Styles
|
||||||
|
#pragma warning restore CA1707 // Naming Styles
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// ctor
|
/// ctor
|
||||||
@@ -469,5 +478,4 @@ namespace CryptoExchange.Net.Authentication
|
|||||||
protected AuthenticationProvider(TApiCredentials credentials) : base(credentials)
|
protected AuthenticationProvider(TApiCredentials credentials) : base(credentials)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
namespace CryptoExchange.Net.Authentication
|
namespace CryptoExchange.Net.Authentication;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Output string type
|
||||||
|
/// </summary>
|
||||||
|
public enum SignOutputType
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Output string type
|
|
||||||
/// </summary>
|
|
||||||
public enum SignOutputType
|
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Hex string
|
/// Hex string
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -13,5 +13,4 @@
|
|||||||
/// Base64 string
|
/// Base64 string
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Base64
|
Base64
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Caching
|
namespace CryptoExchange.Net.Caching;
|
||||||
|
|
||||||
|
internal class MemoryCache
|
||||||
{
|
{
|
||||||
internal class MemoryCache
|
|
||||||
{
|
|
||||||
private readonly ConcurrentDictionary<string, CacheItem> _cache = new ConcurrentDictionary<string, CacheItem>();
|
private readonly ConcurrentDictionary<string, CacheItem> _cache = new ConcurrentDictionary<string, CacheItem>();
|
||||||
private readonly object _lock = new object();
|
private readonly object _lock = new object();
|
||||||
|
|
||||||
@@ -49,5 +49,4 @@ namespace CryptoExchange.Net.Caching
|
|||||||
Value = value;
|
Value = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,18 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using CryptoExchange.Net.Authentication;
|
using CryptoExchange.Net.Authentication;
|
||||||
using CryptoExchange.Net.Interfaces;
|
using CryptoExchange.Net.Interfaces;
|
||||||
using CryptoExchange.Net.Objects;
|
|
||||||
using CryptoExchange.Net.Objects.Errors;
|
using CryptoExchange.Net.Objects.Errors;
|
||||||
using CryptoExchange.Net.Objects.Options;
|
using CryptoExchange.Net.Objects.Options;
|
||||||
using CryptoExchange.Net.SharedApis;
|
using CryptoExchange.Net.SharedApis;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Clients
|
namespace CryptoExchange.Net.Clients;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Base API for all API clients
|
||||||
|
/// </summary>
|
||||||
|
public abstract class BaseApiClient : IDisposable, IBaseApiClient
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Base API for all API clients
|
|
||||||
/// </summary>
|
|
||||||
public abstract class BaseApiClient : IDisposable, IBaseApiClient
|
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Logger
|
/// Logger
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -126,9 +124,17 @@ namespace CryptoExchange.Net.Clients
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Dispose
|
/// Dispose
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual void Dispose()
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Dispose(true);
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Dispose
|
||||||
|
/// </summary>
|
||||||
|
public virtual void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
_disposing = true;
|
_disposing = true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,16 @@
|
|||||||
using CryptoExchange.Net.Authentication;
|
using CryptoExchange.Net.Authentication;
|
||||||
using CryptoExchange.Net.Objects.Options;
|
using CryptoExchange.Net.Objects.Options;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Logging.Abstractions;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Clients
|
namespace CryptoExchange.Net.Clients;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The base for all clients, websocket client and rest client
|
||||||
|
/// </summary>
|
||||||
|
public abstract class BaseClient : IDisposable
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// The base for all clients, websocket client and rest client
|
|
||||||
/// </summary>
|
|
||||||
public abstract class BaseClient : IDisposable
|
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Version of the CryptoExchange.Net base library
|
/// Version of the CryptoExchange.Net base library
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -80,7 +79,7 @@ namespace CryptoExchange.Net.Clients
|
|||||||
throw new ArgumentNullException(nameof(options));
|
throw new ArgumentNullException(nameof(options));
|
||||||
|
|
||||||
ClientOptions = options;
|
ClientOptions = options;
|
||||||
_logger.Log(LogLevel.Trace, $"Client configuration: {options}, CryptoExchange.Net: v{CryptoExchangeLibVersion}, {Exchange}.Net: v{ExchangeLibVersion}");
|
_logger.Log(LogLevel.Trace, "Client configuration: {Options}, CryptoExchange.Net: v{CryptoExchangeVersion}, {Exchange}.Net: v{ExchangeVersion}", options, CryptoExchangeLibVersion, Exchange, ExchangeLibVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -102,6 +101,7 @@ namespace CryptoExchange.Net.Clients
|
|||||||
if (ClientOptions == null)
|
if (ClientOptions == null)
|
||||||
throw new InvalidOperationException("Client should have called Initialize before adding API clients");
|
throw new InvalidOperationException("Client should have called Initialize before adding API clients");
|
||||||
|
|
||||||
|
_logger.Log(LogLevel.Trace, " {ApiClient}, base address: {BaseAddress}", apiClient.GetType().Name, apiClient.BaseAddress);
|
||||||
ApiClients.Add(apiClient);
|
ApiClients.Add(apiClient);
|
||||||
return apiClient;
|
return apiClient;
|
||||||
}
|
}
|
||||||
@@ -119,10 +119,24 @@ namespace CryptoExchange.Net.Clients
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Dispose
|
/// Dispose
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
|
Dispose(true);
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Dispose
|
||||||
|
/// </summary>
|
||||||
|
public virtual void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (disposing)
|
||||||
|
{
|
||||||
|
_logger.Log(LogLevel.Debug, "Disposing client");
|
||||||
foreach (var client in ApiClients)
|
foreach (var client in ApiClients)
|
||||||
client.Dispose();
|
client.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,13 +3,13 @@ using CryptoExchange.Net.Interfaces;
|
|||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Logging.Abstractions;
|
using Microsoft.Extensions.Logging.Abstractions;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Clients
|
namespace CryptoExchange.Net.Clients;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Base rest client
|
||||||
|
/// </summary>
|
||||||
|
public abstract class BaseRestClient : BaseClient, IRestClient
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Base rest client
|
|
||||||
/// </summary>
|
|
||||||
public abstract class BaseRestClient : BaseClient, IRestClient
|
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public int TotalRequestsMade => ApiClients.OfType<RestApiClient>().Sum(s => s.TotalRequestsMade);
|
public int TotalRequestsMade => ApiClients.OfType<RestApiClient>().Sum(s => s.TotalRequestsMade);
|
||||||
|
|
||||||
@@ -21,8 +21,5 @@ namespace CryptoExchange.Net.Clients
|
|||||||
protected BaseRestClient(ILoggerFactory? loggerFactory, string name) : base(loggerFactory, name)
|
protected BaseRestClient(ILoggerFactory? loggerFactory, string name) : base(loggerFactory, name)
|
||||||
{
|
{
|
||||||
_logger = loggerFactory?.CreateLogger(name + ".RestClient") ?? NullLoggerFactory.Instance.CreateLogger(name);
|
_logger = loggerFactory?.CreateLogger(name + ".RestClient") ?? NullLoggerFactory.Instance.CreateLogger(name);
|
||||||
|
|
||||||
LibraryHelpers.StaticLogger = loggerFactory?.CreateLogger("CryptoExchange");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +1,21 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Xml.Linq;
|
|
||||||
using CryptoExchange.Net.Interfaces;
|
using CryptoExchange.Net.Interfaces;
|
||||||
using CryptoExchange.Net.Logging.Extensions;
|
using CryptoExchange.Net.Logging.Extensions;
|
||||||
using CryptoExchange.Net.Objects.Sockets;
|
using CryptoExchange.Net.Objects.Sockets;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Logging.Abstractions;
|
using Microsoft.Extensions.Logging.Abstractions;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Clients
|
namespace CryptoExchange.Net.Clients;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Base for socket client implementations
|
||||||
|
/// </summary>
|
||||||
|
public abstract class BaseSocketClient : BaseClient, ISocketClient
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Base for socket client implementations
|
|
||||||
/// </summary>
|
|
||||||
public abstract class BaseSocketClient : BaseClient, ISocketClient
|
|
||||||
{
|
|
||||||
#region fields
|
#region fields
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -40,8 +39,6 @@ namespace CryptoExchange.Net.Clients
|
|||||||
protected BaseSocketClient(ILoggerFactory? loggerFactory, string name) : base(loggerFactory, name)
|
protected BaseSocketClient(ILoggerFactory? loggerFactory, string name) : base(loggerFactory, name)
|
||||||
{
|
{
|
||||||
_logger = loggerFactory?.CreateLogger(name + ".SocketClient") ?? NullLoggerFactory.Instance.CreateLogger(name);
|
_logger = loggerFactory?.CreateLogger(name + ".SocketClient") ?? NullLoggerFactory.Instance.CreateLogger(name);
|
||||||
|
|
||||||
LibraryHelpers.StaticLogger = loggerFactory?.CreateLogger("CryptoExchange");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -130,5 +127,4 @@ namespace CryptoExchange.Net.Clients
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Clients
|
namespace CryptoExchange.Net.Clients;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Base crypto client
|
||||||
|
/// </summary>
|
||||||
|
public class CryptoBaseClient : IDisposable
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Base crypto client
|
|
||||||
/// </summary>
|
|
||||||
public class CryptoBaseClient : IDisposable
|
|
||||||
{
|
|
||||||
private readonly Dictionary<Type, object> _serviceCache = new Dictionary<Type, object>();
|
private readonly Dictionary<Type, object> _serviceCache = new Dictionary<Type, object>();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -59,9 +59,20 @@ namespace CryptoExchange.Net.Clients
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Dispose
|
/// Dispose
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Dispose()
|
public void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (disposing)
|
||||||
{
|
{
|
||||||
_serviceCache.Clear();
|
_serviceCache.Clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Dispose
|
||||||
|
/// </summary>
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Dispose(true);
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,11 @@
|
|||||||
using CryptoExchange.Net.Interfaces;
|
using CryptoExchange.Net.Interfaces;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Clients
|
namespace CryptoExchange.Net.Clients;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public class CryptoRestClient : CryptoBaseClient, ICryptoRestClient
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
|
||||||
public class CryptoRestClient : CryptoBaseClient, ICryptoRestClient
|
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// ctor
|
/// ctor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -23,5 +20,4 @@ namespace CryptoExchange.Net.Clients
|
|||||||
public CryptoRestClient(IServiceProvider serviceProvider) : base(serviceProvider)
|
public CryptoRestClient(IServiceProvider serviceProvider) : base(serviceProvider)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
using CryptoExchange.Net.Interfaces;
|
using CryptoExchange.Net.Interfaces;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Clients
|
namespace CryptoExchange.Net.Clients;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public class CryptoSocketClient : CryptoBaseClient, ICryptoSocketClient
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
|
||||||
public class CryptoSocketClient : CryptoBaseClient, ICryptoSocketClient
|
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// ctor
|
/// ctor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -20,5 +20,4 @@ namespace CryptoExchange.Net.Clients
|
|||||||
public CryptoSocketClient(IServiceProvider serviceProvider) : base(serviceProvider)
|
public CryptoSocketClient(IServiceProvider serviceProvider) : base(serviceProvider)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,13 +18,13 @@ using CryptoExchange.Net.RateLimiting.Interfaces;
|
|||||||
using CryptoExchange.Net.Requests;
|
using CryptoExchange.Net.Requests;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Clients
|
namespace CryptoExchange.Net.Clients;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Base rest API client for interacting with a REST API
|
||||||
|
/// </summary>
|
||||||
|
public abstract class RestApiClient : BaseApiClient, IRestApiClient
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Base rest API client for interacting with a REST API
|
|
||||||
/// </summary>
|
|
||||||
public abstract class RestApiClient : BaseApiClient, IRestApiClient
|
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public IRequestFactory RequestFactory { get; set; } = new RequestFactory();
|
public IRequestFactory RequestFactory { get; set; } = new RequestFactory();
|
||||||
|
|
||||||
@@ -106,7 +106,7 @@ namespace CryptoExchange.Net.Clients
|
|||||||
options,
|
options,
|
||||||
apiOptions)
|
apiOptions)
|
||||||
{
|
{
|
||||||
RequestFactory.Configure(options, httpClient);
|
RequestFactory.Configure(options.Proxy, options.RequestTimeout, httpClient);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -388,7 +388,7 @@ namespace CryptoExchange.Net.Clients
|
|||||||
queryString = $"?{queryString}";
|
queryString = $"?{queryString}";
|
||||||
|
|
||||||
var uri = new Uri(baseAddress.AppendPath(definition.Path) + queryString);
|
var uri = new Uri(baseAddress.AppendPath(definition.Path) + queryString);
|
||||||
var request = RequestFactory.Create(ClientOptions.HttpVersion, definition.Method, uri, requestId);
|
var request = RequestFactory.Create(definition.Method, uri, requestId);
|
||||||
request.Accept = Constants.JsonContentHeader;
|
request.Accept = Constants.JsonContentHeader;
|
||||||
|
|
||||||
foreach (var header in requestConfiguration.Headers)
|
foreach (var header in requestConfiguration.Headers)
|
||||||
@@ -443,6 +443,9 @@ namespace CryptoExchange.Net.Clients
|
|||||||
{
|
{
|
||||||
response = await request.GetResponseAsync(cancellationToken).ConfigureAwait(false);
|
response = await request.GetResponseAsync(cancellationToken).ConfigureAwait(false);
|
||||||
sw.Stop();
|
sw.Stop();
|
||||||
|
var statusCode = response.StatusCode;
|
||||||
|
var headers = response.ResponseHeaders;
|
||||||
|
var responseLength = response.ContentLength;
|
||||||
responseStream = await response.GetResponseStreamAsync().ConfigureAwait(false);
|
responseStream = await response.GetResponseStreamAsync().ConfigureAwait(false);
|
||||||
var outputOriginalData = ApiOptions.OutputOriginalData ?? ClientOptions.OutputOriginalData;
|
var outputOriginalData = ApiOptions.OutputOriginalData ?? ClientOptions.OutputOriginalData;
|
||||||
|
|
||||||
@@ -472,18 +475,18 @@ namespace CryptoExchange.Net.Clients
|
|||||||
if (error.Code == null || error.Code == 0)
|
if (error.Code == null || error.Code == 0)
|
||||||
error.Code = (int)response.StatusCode;
|
error.Code = (int)response.StatusCode;
|
||||||
|
|
||||||
return new WebCallResult<T>(response.StatusCode, response.HttpVersion, response.ResponseHeaders, sw.Elapsed, response.ContentLength, OutputOriginalData ? accessor.GetOriginalString() : null, request.RequestId, request.Uri.ToString(), request.Content, request.Method, request.GetHeaders(), ResultDataSource.Server, default, error!);
|
return new WebCallResult<T>(response.StatusCode, response.ResponseHeaders, sw.Elapsed, responseLength, OutputOriginalData ? accessor.GetOriginalString() : null, request.RequestId, request.Uri.ToString(), request.Content, request.Method, request.GetHeaders(), ResultDataSource.Server, default, error!);
|
||||||
}
|
}
|
||||||
|
|
||||||
var valid = await accessor.Read(responseStream, outputOriginalData).ConfigureAwait(false);
|
var valid = await accessor.Read(responseStream, outputOriginalData).ConfigureAwait(false);
|
||||||
if (typeof(T) == typeof(object))
|
if (typeof(T) == typeof(object))
|
||||||
// Success status code and expected empty response, assume it's correct
|
// Success status code and expected empty response, assume it's correct
|
||||||
return new WebCallResult<T>(response.StatusCode, response.HttpVersion, response.ResponseHeaders, sw.Elapsed, 0, accessor.OriginalDataAvailable ? accessor.GetOriginalString() : "[Data only available when OutputOriginal = true in client options]", request.RequestId, request.Uri.ToString(), request.Content, request.Method, request.GetHeaders(), ResultDataSource.Server, default, null);
|
return new WebCallResult<T>(statusCode, headers, sw.Elapsed, 0, accessor.OriginalDataAvailable ? accessor.GetOriginalString() : "[Data only available when OutputOriginal = true in client options]", request.RequestId, request.Uri.ToString(), request.Content, request.Method, request.GetHeaders(), ResultDataSource.Server, default, null);
|
||||||
|
|
||||||
if (!valid)
|
if (!valid)
|
||||||
{
|
{
|
||||||
// Invalid json
|
// Invalid json
|
||||||
return new WebCallResult<T>(response.StatusCode, response.HttpVersion, response.ResponseHeaders, sw.Elapsed, response.ContentLength, OutputOriginalData ? accessor.GetOriginalString() : null, request.RequestId, request.Uri.ToString(), request.Content, request.Method, request.GetHeaders(), ResultDataSource.Server, default, valid.Error);
|
return new WebCallResult<T>(response.StatusCode, response.ResponseHeaders, sw.Elapsed, responseLength, OutputOriginalData ? accessor.GetOriginalString() : null, request.RequestId, request.Uri.ToString(), request.Content, request.Method, request.GetHeaders(), ResultDataSource.Server, default, valid.Error);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Json response received
|
// Json response received
|
||||||
@@ -500,55 +503,33 @@ namespace CryptoExchange.Net.Clients
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Success status code, but TryParseError determined it was an error response
|
// Success status code, but TryParseError determined it was an error response
|
||||||
return new WebCallResult<T>(response.StatusCode, response.HttpVersion, response.ResponseHeaders, sw.Elapsed, response.ContentLength, OutputOriginalData ? accessor.GetOriginalString() : null, request.RequestId, request.Uri.ToString(), request.Content, request.Method, request.GetHeaders(), ResultDataSource.Server, default, parsedError);
|
return new WebCallResult<T>(response.StatusCode, response.ResponseHeaders, sw.Elapsed, responseLength, OutputOriginalData ? accessor.GetOriginalString() : null, request.RequestId, request.Uri.ToString(), request.Content, request.Method, request.GetHeaders(), ResultDataSource.Server, default, parsedError);
|
||||||
}
|
}
|
||||||
|
|
||||||
var deserializeResult = accessor.Deserialize<T>();
|
var deserializeResult = accessor.Deserialize<T>();
|
||||||
return new WebCallResult<T>(response.StatusCode, response.HttpVersion, response.ResponseHeaders, sw.Elapsed, response.ContentLength, OutputOriginalData ? accessor.GetOriginalString() : null, request.RequestId, request.Uri.ToString(), request.Content, request.Method, request.GetHeaders(), ResultDataSource.Server, deserializeResult.Data, deserializeResult.Error);
|
return new WebCallResult<T>(response.StatusCode, response.ResponseHeaders, sw.Elapsed, responseLength, OutputOriginalData ? accessor.GetOriginalString() : null, request.RequestId, request.Uri.ToString(), request.Content, request.Method, request.GetHeaders(), ResultDataSource.Server, deserializeResult.Data, deserializeResult.Error);
|
||||||
}
|
}
|
||||||
catch (HttpRequestException requestException)
|
catch (HttpRequestException requestException)
|
||||||
{
|
{
|
||||||
// Request exception, can't reach server for instance
|
// Request exception, can't reach server for instance
|
||||||
var error = new WebError(requestException.Message, requestException);
|
var error = new WebError(requestException.Message, requestException);
|
||||||
return new WebCallResult<T>(null, null, null, sw.Elapsed, null, null, request.RequestId, request.Uri.ToString(), request.Content, request.Method, request.GetHeaders(), ResultDataSource.Server, default, error);
|
return new WebCallResult<T>(null, null, sw.Elapsed, null, null, request.RequestId, request.Uri.ToString(), request.Content, request.Method, request.GetHeaders(), ResultDataSource.Server, default, error);
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException canceledException)
|
catch (OperationCanceledException canceledException)
|
||||||
{
|
{
|
||||||
if (cancellationToken != default && canceledException.CancellationToken == cancellationToken)
|
if (cancellationToken != default && canceledException.CancellationToken == cancellationToken)
|
||||||
{
|
{
|
||||||
// Cancellation token canceled by caller
|
// Cancellation token canceled by caller
|
||||||
return new WebCallResult<T>(null, null, null, sw.Elapsed, null, null, request.RequestId, request.Uri.ToString(), request.Content, request.Method, request.GetHeaders(), ResultDataSource.Server, default, new CancellationRequestedError(canceledException));
|
return new WebCallResult<T>(null, null, sw.Elapsed, null, null, request.RequestId, request.Uri.ToString(), request.Content, request.Method, request.GetHeaders(), ResultDataSource.Server, default, new CancellationRequestedError(canceledException));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Request timed out
|
// Request timed out
|
||||||
var error = new WebError($"Request timed out", exception: canceledException);
|
var error = new WebError($"Request timed out", exception: canceledException);
|
||||||
error.ErrorType = ErrorType.Timeout;
|
error.ErrorType = ErrorType.Timeout;
|
||||||
return new WebCallResult<T>(null, null, null, sw.Elapsed, null, null, request.RequestId, request.Uri.ToString(), request.Content, request.Method, request.GetHeaders(), ResultDataSource.Server, default, error);
|
return new WebCallResult<T>(null, null, sw.Elapsed, null, null, request.RequestId, request.Uri.ToString(), request.Content, request.Method, request.GetHeaders(), ResultDataSource.Server, default, error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (ArgumentException argumentException)
|
|
||||||
{
|
|
||||||
if (argumentException.Message.StartsWith("Only HTTP/"))
|
|
||||||
{
|
|
||||||
// Unsupported HTTP version error .net framework
|
|
||||||
var error = ArgumentError.Invalid(nameof(RestExchangeOptions.HttpVersion), $"Invalid HTTP version {request.HttpVersion}: " + argumentException.Message);
|
|
||||||
return new WebCallResult<T>(null, null, null, sw.Elapsed, null, null, request.RequestId, request.Uri.ToString(), request.Content, request.Method, request.GetHeaders(), ResultDataSource.Server, default, error);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
catch (NotSupportedException notSupportedException)
|
|
||||||
{
|
|
||||||
if (notSupportedException.Message.StartsWith("Request version value must be one of"))
|
|
||||||
{
|
|
||||||
// Unsupported HTTP version error dotnet code
|
|
||||||
var error = ArgumentError.Invalid(nameof(RestExchangeOptions.HttpVersion), $"Invalid HTTP version {request.HttpVersion}: " + notSupportedException.Message);
|
|
||||||
return new WebCallResult<T>(null, null, null, sw.Elapsed, null, null, request.RequestId, request.Uri.ToString(), request.Content, request.Method, request.GetHeaders(), ResultDataSource.Server, default, error);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
accessor?.Clear();
|
accessor?.Clear();
|
||||||
@@ -656,7 +637,7 @@ namespace CryptoExchange.Net.Clients
|
|||||||
{
|
{
|
||||||
// Handle retry after header
|
// Handle retry after header
|
||||||
var retryAfterHeader = responseHeaders.SingleOrDefault(r => r.Key.Equals("Retry-After", StringComparison.InvariantCultureIgnoreCase));
|
var retryAfterHeader = responseHeaders.SingleOrDefault(r => r.Key.Equals("Retry-After", StringComparison.InvariantCultureIgnoreCase));
|
||||||
if (retryAfterHeader.Value?.Any() != true)
|
if (!(retryAfterHeader.Value.Length > 0))
|
||||||
return new ServerRateLimitError();
|
return new ServerRateLimitError();
|
||||||
|
|
||||||
var value = retryAfterHeader.Value.First();
|
var value = retryAfterHeader.Value.First();
|
||||||
@@ -693,21 +674,21 @@ namespace CryptoExchange.Net.Clients
|
|||||||
{
|
{
|
||||||
base.SetOptions(options);
|
base.SetOptions(options);
|
||||||
|
|
||||||
RequestFactory.UpdateSettings(options.Proxy, options.RequestTimeout ?? ClientOptions.RequestTimeout, ClientOptions.HttpKeepAliveInterval);
|
RequestFactory.UpdateSettings(options.Proxy, options.RequestTimeout ?? ClientOptions.RequestTimeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal async Task<WebCallResult<bool>> SyncTimeAsync()
|
internal async Task<WebCallResult<bool>> SyncTimeAsync()
|
||||||
{
|
{
|
||||||
var timeSyncParams = GetTimeSyncInfo();
|
var timeSyncParams = GetTimeSyncInfo();
|
||||||
if (timeSyncParams == null)
|
if (timeSyncParams == null)
|
||||||
return new WebCallResult<bool>(null, null, null, null, null, null, null, null, null, null, null, ResultDataSource.Server, true, null);
|
return new WebCallResult<bool>(null, null, null, null, null, null, null, null, null, null, ResultDataSource.Server, true, null);
|
||||||
|
|
||||||
if (await timeSyncParams.TimeSyncState.Semaphore.WaitAsync(0).ConfigureAwait(false))
|
if (await timeSyncParams.TimeSyncState.Semaphore.WaitAsync(0).ConfigureAwait(false))
|
||||||
{
|
{
|
||||||
if (!timeSyncParams.SyncTime || DateTime.UtcNow - timeSyncParams.TimeSyncState.LastSyncTime < timeSyncParams.RecalculationInterval)
|
if (!timeSyncParams.SyncTime || DateTime.UtcNow - timeSyncParams.TimeSyncState.LastSyncTime < timeSyncParams.RecalculationInterval)
|
||||||
{
|
{
|
||||||
timeSyncParams.TimeSyncState.Semaphore.Release();
|
timeSyncParams.TimeSyncState.Semaphore.Release();
|
||||||
return new WebCallResult<bool>(null, null, null, null, null, null, null, null, null, null, null, ResultDataSource.Server, true, null);
|
return new WebCallResult<bool>(null, null, null, null, null, null, null, null, null, null, ResultDataSource.Server, true, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
var localTime = DateTime.UtcNow;
|
var localTime = DateTime.UtcNow;
|
||||||
@@ -736,12 +717,11 @@ namespace CryptoExchange.Net.Clients
|
|||||||
timeSyncParams.TimeSyncState.Semaphore.Release();
|
timeSyncParams.TimeSyncState.Semaphore.Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
return new WebCallResult<bool>(null, null, null, null, null, null, null, null, null, null, null, ResultDataSource.Server, true, null);
|
return new WebCallResult<bool>(null, null, null, null, null, null, null, null, null, null, ResultDataSource.Server, true, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool ShouldCache(RequestDefinition definition)
|
private bool ShouldCache(RequestDefinition definition)
|
||||||
=> ClientOptions.CachingEnabled
|
=> ClientOptions.CachingEnabled
|
||||||
&& definition.Method == HttpMethod.Get
|
&& definition.Method == HttpMethod.Get
|
||||||
&& !definition.PreventCaching;
|
&& !definition.PreventCaching;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,13 +17,13 @@ using System.Text;
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Clients
|
namespace CryptoExchange.Net.Clients;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Base socket API client for interaction with a websocket API
|
||||||
|
/// </summary>
|
||||||
|
public abstract class SocketApiClient : BaseApiClient, ISocketApiClient
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Base socket API client for interaction with a websocket API
|
|
||||||
/// </summary>
|
|
||||||
public abstract class SocketApiClient : BaseApiClient, ISocketApiClient
|
|
||||||
{
|
|
||||||
#region Fields
|
#region Fields
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public IWebsocketFactory SocketFactory { get; set; } = new WebsocketFactory();
|
public IWebsocketFactory SocketFactory { get; set; } = new WebsocketFactory();
|
||||||
@@ -86,7 +86,7 @@ namespace CryptoExchange.Net.Clients
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether to continue processing and forward unparsable messages to handlers
|
/// Whether to continue processing and forward unparsable messages to handlers
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected internal bool ProcessUnparsableMessages { get; set; } = false;
|
protected internal bool ProcessUnparsableMessages { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public double IncomingKbps
|
public double IncomingKbps
|
||||||
@@ -227,7 +227,7 @@ namespace CryptoExchange.Net.Clients
|
|||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
// Get a new or existing socket connection
|
// Get a new or existing socket connection
|
||||||
var socketResult = await GetSocketConnection(url, subscription.Authenticated, false, ct, subscription.Topic).ConfigureAwait(false);
|
var socketResult = await GetSocketConnection(url, subscription.Authenticated, false, subscription.Topic).ConfigureAwait(false);
|
||||||
if (!socketResult)
|
if (!socketResult)
|
||||||
return socketResult.As<UpdateSubscription>(null);
|
return socketResult.As<UpdateSubscription>(null);
|
||||||
|
|
||||||
@@ -269,7 +269,6 @@ namespace CryptoExchange.Net.Clients
|
|||||||
return new CallResult<UpdateSubscription>(new ServerError(new ErrorInfo(ErrorType.WebsocketPaused, "Socket is paused")));
|
return new CallResult<UpdateSubscription>(new ServerError(new ErrorInfo(ErrorType.WebsocketPaused, "Socket is paused")));
|
||||||
}
|
}
|
||||||
|
|
||||||
subscription.Status = SubscriptionStatus.Subscribing;
|
|
||||||
var waitEvent = new AsyncResetEvent(false);
|
var waitEvent = new AsyncResetEvent(false);
|
||||||
var subQuery = subscription.CreateSubscriptionQuery(socketConnection);
|
var subQuery = subscription.CreateSubscriptionQuery(socketConnection);
|
||||||
if (subQuery != null)
|
if (subQuery != null)
|
||||||
@@ -280,7 +279,7 @@ namespace CryptoExchange.Net.Clients
|
|||||||
{
|
{
|
||||||
waitEvent?.Set();
|
waitEvent?.Set();
|
||||||
var isTimeout = subResult.Error is CancellationRequestedError;
|
var isTimeout = subResult.Error is CancellationRequestedError;
|
||||||
if (isTimeout && subscription.Status == SubscriptionStatus.Subscribed)
|
if (isTimeout && subscription.Confirmed)
|
||||||
{
|
{
|
||||||
// No response received, but the subscription did receive updates. We'll assume success
|
// No response received, but the subscription did receive updates. We'll assume success
|
||||||
}
|
}
|
||||||
@@ -288,7 +287,6 @@ namespace CryptoExchange.Net.Clients
|
|||||||
{
|
{
|
||||||
_logger.FailedToSubscribe(socketConnection.SocketId, subResult.Error?.ToString());
|
_logger.FailedToSubscribe(socketConnection.SocketId, subResult.Error?.ToString());
|
||||||
// If this was a timeout we still need to send an unsubscribe to prevent messages coming in later
|
// If this was a timeout we still need to send an unsubscribe to prevent messages coming in later
|
||||||
subscription.Status = SubscriptionStatus.Pending;
|
|
||||||
await socketConnection.CloseAsync(subscription).ConfigureAwait(false);
|
await socketConnection.CloseAsync(subscription).ConfigureAwait(false);
|
||||||
return new CallResult<UpdateSubscription>(subResult.Error!);
|
return new CallResult<UpdateSubscription>(subResult.Error!);
|
||||||
}
|
}
|
||||||
@@ -297,7 +295,7 @@ namespace CryptoExchange.Net.Clients
|
|||||||
subscription.HandleSubQueryResponse(subQuery.Response!);
|
subscription.HandleSubQueryResponse(subQuery.Response!);
|
||||||
}
|
}
|
||||||
|
|
||||||
subscription.Status = SubscriptionStatus.Subscribed;
|
subscription.Confirmed = true;
|
||||||
if (ct != default)
|
if (ct != default)
|
||||||
{
|
{
|
||||||
subscription.CancellationTokenRegistration = ct.Register(async () =>
|
subscription.CancellationTokenRegistration = ct.Register(async () =>
|
||||||
@@ -342,10 +340,16 @@ namespace CryptoExchange.Net.Clients
|
|||||||
|
|
||||||
SocketConnection socketConnection;
|
SocketConnection socketConnection;
|
||||||
var released = false;
|
var released = false;
|
||||||
await semaphoreSlim.WaitAsync().ConfigureAwait(false);
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var socketResult = await GetSocketConnection(url, query.Authenticated, true, ct).ConfigureAwait(false);
|
await semaphoreSlim.WaitAsync(ct).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch (OperationCanceledException) { }
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var socketResult = await GetSocketConnection(url, query.Authenticated, true).ConfigureAwait(false);
|
||||||
if (!socketResult)
|
if (!socketResult)
|
||||||
return socketResult.As<THandlerResponse>(default);
|
return socketResult.As<THandlerResponse>(default);
|
||||||
|
|
||||||
@@ -397,7 +401,13 @@ namespace CryptoExchange.Net.Clients
|
|||||||
return connectResult;
|
return connectResult;
|
||||||
|
|
||||||
if (ClientOptions.DelayAfterConnect != TimeSpan.Zero)
|
if (ClientOptions.DelayAfterConnect != TimeSpan.Zero)
|
||||||
await Task.Delay(ClientOptions.DelayAfterConnect).ConfigureAwait(false);
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await Task.Delay(ClientOptions.DelayAfterConnect, ct).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch (OperationCanceledException) { }
|
||||||
|
}
|
||||||
|
|
||||||
if (!authenticated || socket.Authenticated)
|
if (!authenticated || socket.Authenticated)
|
||||||
return CallResult.SuccessResult;
|
return CallResult.SuccessResult;
|
||||||
@@ -496,56 +506,25 @@ namespace CryptoExchange.Net.Clients
|
|||||||
/// <param name="address">The address the socket is for</param>
|
/// <param name="address">The address the socket is for</param>
|
||||||
/// <param name="authenticated">Whether the socket should be authenticated</param>
|
/// <param name="authenticated">Whether the socket should be authenticated</param>
|
||||||
/// <param name="dedicatedRequestConnection">Whether a dedicated request connection should be returned</param>
|
/// <param name="dedicatedRequestConnection">Whether a dedicated request connection should be returned</param>
|
||||||
/// <param name="ct">Cancellation token</param>
|
|
||||||
/// <param name="topic">The subscription topic, can be provided when multiple of the same topics are not allowed on a connection</param>
|
/// <param name="topic">The subscription topic, can be provided when multiple of the same topics are not allowed on a connection</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
protected virtual async Task<CallResult<SocketConnection>> GetSocketConnection(string address, bool authenticated, bool dedicatedRequestConnection, CancellationToken ct, string? topic = null)
|
protected virtual async Task<CallResult<SocketConnection>> GetSocketConnection(string address, bool authenticated, bool dedicatedRequestConnection, string? topic = null)
|
||||||
{
|
{
|
||||||
var socketQuery = socketConnections.Where(s => s.Value.Tag.TrimEnd('/') == address.TrimEnd('/')
|
var socketQuery = socketConnections.Where(s => (s.Value.Status == SocketConnection.SocketStatus.None || s.Value.Status == SocketConnection.SocketStatus.Connected)
|
||||||
|
&& s.Value.Tag.TrimEnd('/') == address.TrimEnd('/')
|
||||||
&& s.Value.ApiClient.GetType() == GetType()
|
&& s.Value.ApiClient.GetType() == GetType()
|
||||||
&& (AllowTopicsOnTheSameConnection || !s.Value.Topics.Contains(topic)))
|
&& (s.Value.Authenticated == authenticated || !authenticated)
|
||||||
.Select(x => x.Value)
|
&& (AllowTopicsOnTheSameConnection || !s.Value.Topics.Contains(topic))
|
||||||
.ToList();
|
&& s.Value.Connected);
|
||||||
|
|
||||||
// If all current socket connections are reconnecting or resubscribing wait for that to finish as we can probably use the existing connection
|
SocketConnection connection;
|
||||||
var delayStart = DateTime.UtcNow;
|
|
||||||
var delayed = false;
|
|
||||||
while (socketQuery.Count >= 1 && socketQuery.All(x => x.Status == SocketConnection.SocketStatus.Reconnecting || x.Status == SocketConnection.SocketStatus.Resubscribing))
|
|
||||||
{
|
|
||||||
if (DateTime.UtcNow - delayStart > TimeSpan.FromSeconds(10))
|
|
||||||
{
|
|
||||||
if (socketQuery.Count >= 1 && socketQuery.All(x => x.Status == SocketConnection.SocketStatus.Reconnecting || x.Status == SocketConnection.SocketStatus.Resubscribing))
|
|
||||||
{
|
|
||||||
// If after this time we still trying to reconnect/reprocess there is some issue in the connection
|
|
||||||
_logger.TimeoutWaitingForReconnectingSocket();
|
|
||||||
return new CallResult<SocketConnection>(new CantConnectError());
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
delayed = true;
|
|
||||||
try { await Task.Delay(50, ct).ConfigureAwait(false); } catch (Exception) { }
|
|
||||||
|
|
||||||
if (ct.IsCancellationRequested)
|
|
||||||
return new CallResult<SocketConnection>(new CancellationRequestedError());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (delayed)
|
|
||||||
_logger.WaitedForReconnectingSocket((long)(DateTime.UtcNow - delayStart).TotalMilliseconds);
|
|
||||||
|
|
||||||
socketQuery = socketQuery.Where(s => (s.Status == SocketConnection.SocketStatus.None || s.Status == SocketConnection.SocketStatus.Connected)
|
|
||||||
&& (s.Authenticated == authenticated || !authenticated)
|
|
||||||
&& s.Connected).ToList();
|
|
||||||
|
|
||||||
SocketConnection? connection;
|
|
||||||
if (!dedicatedRequestConnection)
|
if (!dedicatedRequestConnection)
|
||||||
{
|
{
|
||||||
connection = socketQuery.Where(s => !s.DedicatedRequestConnection.IsDedicatedRequestConnection).OrderBy(s => s.UserSubscriptionCount).FirstOrDefault();
|
connection = socketQuery.Where(s => !s.Value.DedicatedRequestConnection.IsDedicatedRequestConnection).OrderBy(s => s.Value.UserSubscriptionCount).FirstOrDefault().Value;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
connection = socketQuery.Where(s => s.DedicatedRequestConnection.IsDedicatedRequestConnection).FirstOrDefault();
|
connection = socketQuery.Where(s => s.Value.DedicatedRequestConnection.IsDedicatedRequestConnection).FirstOrDefault().Value;
|
||||||
if (connection != null && !connection.DedicatedRequestConnection.Authenticated)
|
if (connection != null && !connection.DedicatedRequestConnection.Authenticated)
|
||||||
// Mark dedicated request connection as authenticated if the request is authenticated
|
// Mark dedicated request connection as authenticated if the request is authenticated
|
||||||
connection.DedicatedRequestConnection.Authenticated = authenticated;
|
connection.DedicatedRequestConnection.Authenticated = authenticated;
|
||||||
@@ -553,13 +532,10 @@ namespace CryptoExchange.Net.Clients
|
|||||||
|
|
||||||
if (connection != null)
|
if (connection != null)
|
||||||
{
|
{
|
||||||
if (connection.UserSubscriptionCount < ClientOptions.SocketSubscriptionsCombineTarget
|
if (connection.UserSubscriptionCount < ClientOptions.SocketSubscriptionsCombineTarget || (socketConnections.Count >= (ApiOptions.MaxSocketConnections ?? ClientOptions.MaxSocketConnections) && socketConnections.All(s => s.Value.UserSubscriptionCount >= ClientOptions.SocketSubscriptionsCombineTarget)))
|
||||||
|| (socketConnections.Count >= (ApiOptions.MaxSocketConnections ?? ClientOptions.MaxSocketConnections) && socketConnections.All(s => s.Value.UserSubscriptionCount >= ClientOptions.SocketSubscriptionsCombineTarget)))
|
|
||||||
{
|
|
||||||
// Use existing socket if it has less than target connections OR it has the least connections and we can't make new
|
// Use existing socket if it has less than target connections OR it has the least connections and we can't make new
|
||||||
return new CallResult<SocketConnection>(connection);
|
return new CallResult<SocketConnection>(connection);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
var connectionAddress = await GetConnectionUrlAsync(address, authenticated).ConfigureAwait(false);
|
var connectionAddress = await GetConnectionUrlAsync(address, authenticated).ConfigureAwait(false);
|
||||||
if (!connectionAddress)
|
if (!connectionAddress)
|
||||||
@@ -752,7 +728,7 @@ namespace CryptoExchange.Net.Clients
|
|||||||
{
|
{
|
||||||
foreach (var item in DedicatedConnectionConfigs)
|
foreach (var item in DedicatedConnectionConfigs)
|
||||||
{
|
{
|
||||||
var socketResult = await GetSocketConnection(item.SocketAddress, item.Authenticated, true, CancellationToken.None).ConfigureAwait(false);
|
var socketResult = await GetSocketConnection(item.SocketAddress, item.Authenticated, true).ConfigureAwait(false);
|
||||||
if (!socketResult)
|
if (!socketResult)
|
||||||
return socketResult.AsDataless();
|
return socketResult.AsDataless();
|
||||||
|
|
||||||
@@ -849,7 +825,7 @@ namespace CryptoExchange.Net.Clients
|
|||||||
cs.SubscriptionStates.ForEach(subState =>
|
cs.SubscriptionStates.ForEach(subState =>
|
||||||
{
|
{
|
||||||
sb.AppendLine($"\t\t\tId: {subState.Id}");
|
sb.AppendLine($"\t\t\tId: {subState.Id}");
|
||||||
sb.AppendLine($"\t\t\tStatus: {subState.Status}");
|
sb.AppendLine($"\t\t\tConfirmed: {subState.Confirmed}");
|
||||||
sb.AppendLine($"\t\t\tInvocations: {subState.Invocations}");
|
sb.AppendLine($"\t\t\tInvocations: {subState.Invocations}");
|
||||||
sb.AppendLine($"\t\t\tIdentifiers: [{subState.ListenMatcher.ToString()}]");
|
sb.AppendLine($"\t\t\tIdentifiers: [{subState.ListenMatcher.ToString()}]");
|
||||||
});
|
});
|
||||||
@@ -863,8 +839,11 @@ namespace CryptoExchange.Net.Clients
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Dispose the client
|
/// Dispose the client
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public override void Dispose()
|
public override void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
|
if (disposing)
|
||||||
|
return;
|
||||||
|
|
||||||
_disposing = true;
|
_disposing = true;
|
||||||
var tasks = new List<Task>();
|
var tasks = new List<Task>();
|
||||||
{
|
{
|
||||||
@@ -879,7 +858,7 @@ namespace CryptoExchange.Net.Clients
|
|||||||
}
|
}
|
||||||
|
|
||||||
semaphoreSlim?.Dispose();
|
semaphoreSlim?.Dispose();
|
||||||
base.Dispose();
|
base.Dispose(disposing);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -897,5 +876,4 @@ namespace CryptoExchange.Net.Clients
|
|||||||
/// <param name="data"></param>
|
/// <param name="data"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public virtual ReadOnlyMemory<byte> PreprocessStreamMessage(SocketConnection connection, WebSocketMessageType type, ReadOnlyMemory<byte> data) => data;
|
public virtual ReadOnlyMemory<byte> PreprocessStreamMessage(SocketConnection connection, WebSocketMessageType type, ReadOnlyMemory<byte> data) => data;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Converters
|
namespace CryptoExchange.Net.Converters;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Mark property as an index in the array
|
||||||
|
/// </summary>
|
||||||
|
[AttributeUsage(AttributeTargets.Property)]
|
||||||
|
public class ArrayPropertyAttribute : Attribute
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Mark property as an index in the array
|
|
||||||
/// </summary>
|
|
||||||
[AttributeUsage(AttributeTargets.Property)]
|
|
||||||
public class ArrayPropertyAttribute : Attribute
|
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The index in the array
|
/// The index in the array
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -21,5 +21,4 @@ namespace CryptoExchange.Net.Converters
|
|||||||
{
|
{
|
||||||
Index = index;
|
Index = index;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,14 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Converters
|
namespace CryptoExchange.Net.Converters;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Caching for JsonSerializerContext instances
|
||||||
|
/// </summary>
|
||||||
|
public static class JsonSerializerContextCache
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Caching for JsonSerializerContext instances
|
|
||||||
/// </summary>
|
|
||||||
public static class JsonSerializerContextCache
|
|
||||||
{
|
|
||||||
private static ConcurrentDictionary<Type, JsonSerializerContext> _cache = new ConcurrentDictionary<Type, JsonSerializerContext>();
|
private static ConcurrentDictionary<Type, JsonSerializerContext> _cache = new ConcurrentDictionary<Type, JsonSerializerContext>();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -27,5 +25,4 @@ namespace CryptoExchange.Net.Converters
|
|||||||
_cache[contextType] = instance;
|
_cache[contextType] = instance;
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
namespace CryptoExchange.Net.Converters.MessageParsing
|
namespace CryptoExchange.Net.Converters.MessageParsing;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Node accessor
|
||||||
|
/// </summary>
|
||||||
|
public readonly struct NodeAccessor
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Node accessor
|
|
||||||
/// </summary>
|
|
||||||
public readonly struct NodeAccessor
|
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Index
|
/// Index
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -45,5 +45,4 @@
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static NodeAccessor PropertyName() { return new NodeAccessor(null, null, 2); }
|
public static NodeAccessor PropertyName() { return new NodeAccessor(null, null, 2); }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Converters.MessageParsing
|
namespace CryptoExchange.Net.Converters.MessageParsing;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Message access definition
|
||||||
|
/// </summary>
|
||||||
|
public readonly struct MessagePath : IEnumerable<NodeAccessor>
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Message access definition
|
|
||||||
/// </summary>
|
|
||||||
public readonly struct MessagePath : IEnumerable<NodeAccessor>
|
|
||||||
{
|
|
||||||
private readonly List<NodeAccessor> _path;
|
private readonly List<NodeAccessor> _path;
|
||||||
|
|
||||||
internal void Add(NodeAccessor node)
|
internal void Add(NodeAccessor node)
|
||||||
@@ -46,5 +46,4 @@ namespace CryptoExchange.Net.Converters.MessageParsing
|
|||||||
{
|
{
|
||||||
return GetEnumerator();
|
return GetEnumerator();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
namespace CryptoExchange.Net.Converters.MessageParsing
|
namespace CryptoExchange.Net.Converters.MessageParsing;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Message path extension methods
|
||||||
|
/// </summary>
|
||||||
|
public static class MessagePathExtension
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Message path extension methods
|
|
||||||
/// </summary>
|
|
||||||
public static class MessagePathExtension
|
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Add a string node accessor
|
/// Add a string node accessor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -39,5 +39,4 @@
|
|||||||
path.Add(NodeAccessor.Int(index));
|
path.Add(NodeAccessor.Int(index));
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
namespace CryptoExchange.Net.Converters.MessageParsing
|
namespace CryptoExchange.Net.Converters.MessageParsing;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Message node type
|
||||||
|
/// </summary>
|
||||||
|
public enum NodeType
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Message node type
|
|
||||||
/// </summary>
|
|
||||||
public enum NodeType
|
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Array node
|
/// Array node
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -17,5 +17,4 @@
|
|||||||
/// Value node
|
/// Value node
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Value
|
Value
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,28 +1,27 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using CryptoExchange.Net.Attributes;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Diagnostics;
|
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Converters.SystemTextJson
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Converter for arrays to objects. Can deserialize data like [0.1, 0.2, "test"] to an object. Mapping is done by marking the class with [JsonConverter(typeof(ArrayConverter))] and the properties
|
|
||||||
/// with [ArrayProperty(x)] where x is the index of the property in the array
|
|
||||||
/// </summary>
|
|
||||||
#if NET5_0_OR_GREATER
|
#if NET5_0_OR_GREATER
|
||||||
public class ArrayConverter<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] T> : JsonConverter<T> where T : new()
|
using System.Diagnostics.CodeAnalysis;
|
||||||
#else
|
|
||||||
public class ArrayConverter<T> : JsonConverter<T> where T : new()
|
|
||||||
#endif
|
#endif
|
||||||
{
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace CryptoExchange.Net.Converters.SystemTextJson;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converter for arrays to objects. Can deserialize data like [0.1, 0.2, "test"] to an object. Mapping is done by marking the class with [JsonConverter(typeof(ArrayConverter))] and the properties
|
||||||
|
/// with [ArrayProperty(x)] where x is the index of the property in the array
|
||||||
|
/// </summary>
|
||||||
|
#if NET5_0_OR_GREATER
|
||||||
|
public class ArrayConverter<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] T> : JsonConverter<T> where T : new()
|
||||||
|
#else
|
||||||
|
public class ArrayConverter<T> : JsonConverter<T> where T : new()
|
||||||
|
#endif
|
||||||
|
{
|
||||||
private static readonly Lazy<List<ArrayPropertyInfo>> _typePropertyInfo = new Lazy<List<ArrayPropertyInfo>>(CacheTypeAttributes, LazyThreadSafetyMode.PublicationOnly);
|
private static readonly Lazy<List<ArrayPropertyInfo>> _typePropertyInfo = new Lazy<List<ArrayPropertyInfo>>(CacheTypeAttributes, LazyThreadSafetyMode.PublicationOnly);
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -228,7 +227,6 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
|
|||||||
public JsonConverter? JsonConverter { get; set; }
|
public JsonConverter? JsonConverter { get; set; }
|
||||||
public bool DefaultDeserialization { get; set; }
|
public bool DefaultDeserialization { get; set; }
|
||||||
public Type TargetType { get; set; } = null!;
|
public Type TargetType { get; set; } = null!;
|
||||||
public JsonSerializerOptions? JsonSerializerOptions { get; set; } = null;
|
public JsonSerializerOptions? JsonSerializerOptions { get; set; }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Converters.SystemTextJson
|
namespace CryptoExchange.Net.Converters.SystemTextJson;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Decimal converter that handles overflowing decimal values (by setting it to decimal.MaxValue)
|
||||||
|
/// </summary>
|
||||||
|
public class BigDecimalConverter : JsonConverter<decimal>
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Decimal converter that handles overflowing decimal values (by setting it to decimal.MaxValue)
|
|
||||||
/// </summary>
|
|
||||||
public class BigDecimalConverter : JsonConverter<decimal>
|
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override decimal Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
public override decimal Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||||
{
|
{
|
||||||
@@ -42,5 +42,4 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
|
|||||||
{
|
{
|
||||||
writer.WriteNumberValue(value);
|
writer.WriteNumberValue(value);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,16 @@
|
|||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Runtime.Serialization;
|
using System.Runtime.Serialization;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Converters.SystemTextJson
|
namespace CryptoExchange.Net.Converters.SystemTextJson;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Bool converter
|
||||||
|
/// </summary>
|
||||||
|
public class BoolConverter : JsonConverterFactory
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Bool converter
|
|
||||||
/// </summary>
|
|
||||||
public class BoolConverter : JsonConverterFactory
|
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override bool CanConvert(Type typeToConvert)
|
public override bool CanConvert(Type typeToConvert)
|
||||||
{
|
{
|
||||||
@@ -29,7 +28,7 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
|
|||||||
public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||||
=> (T)((object?)ReadBool(ref reader, typeToConvert, options) ?? default(T))!;
|
=> (T)((object?)ReadBool(ref reader, typeToConvert, options) ?? default(T))!;
|
||||||
|
|
||||||
public bool? ReadBool(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
public static bool? ReadBool(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||||
{
|
{
|
||||||
if (reader.TokenType == JsonTokenType.True)
|
if (reader.TokenType == JsonTokenType.True)
|
||||||
return true;
|
return true;
|
||||||
@@ -48,7 +47,7 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
|
|||||||
if (string.IsNullOrEmpty(value))
|
if (string.IsNullOrEmpty(value))
|
||||||
{
|
{
|
||||||
if (typeToConvert == typeof(bool))
|
if (typeToConvert == typeof(bool))
|
||||||
LibraryHelpers.StaticLogger?.LogWarning("Received null bool value, but property type is not a nullable bool");
|
Trace.WriteLine($"{DateTime.Now:yyyy/MM/dd HH:mm:ss:fff} | Warning | Received null bool value, but property type is not a nullable bool");
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,5 +80,4 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,23 +1,23 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
#if NET5_0_OR_GREATER
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
#endif
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Converters.SystemTextJson
|
namespace CryptoExchange.Net.Converters.SystemTextJson;
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Converter for comma separated enum values
|
/// Converter for comma separated enum values
|
||||||
/// </summary>
|
/// </summary>
|
||||||
#if NET5_0_OR_GREATER
|
#if NET5_0_OR_GREATER
|
||||||
public class CommaSplitEnumConverter<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor | DynamicallyAccessedMemberTypes.PublicFields)] T> : JsonConverter<T[]> where T : struct, Enum
|
public class CommaSplitEnumConverter<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor | DynamicallyAccessedMemberTypes.PublicFields)] T> : JsonConverter<T[]> where T : struct, Enum
|
||||||
#else
|
#else
|
||||||
public class CommaSplitEnumConverter<T> : JsonConverter<T[]> where T : struct, Enum
|
public class CommaSplitEnumConverter<T> : JsonConverter<T[]> where T : struct, Enum
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override T[]? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
public override T[]? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||||
{
|
{
|
||||||
@@ -33,5 +33,4 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
|
|||||||
{
|
{
|
||||||
writer.WriteStringValue(string.Join(",", value.Select(x => EnumConverter.GetString(x))));
|
writer.WriteStringValue(string.Join(",", value.Select(x => EnumConverter.GetString(x))));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
@@ -6,17 +5,17 @@ using System.Globalization;
|
|||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Converters.SystemTextJson
|
namespace CryptoExchange.Net.Converters.SystemTextJson;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Date time converter
|
||||||
|
/// </summary>
|
||||||
|
public class DateTimeConverter : JsonConverterFactory
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Date time converter
|
|
||||||
/// </summary>
|
|
||||||
public class DateTimeConverter : JsonConverterFactory
|
|
||||||
{
|
|
||||||
private static readonly DateTime _epoch = new(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
private static readonly DateTime _epoch = new(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
||||||
private const long _ticksPerSecond = TimeSpan.TicksPerMillisecond * 1000;
|
private const long _ticksPerSecond = TimeSpan.TicksPerMillisecond * 1000;
|
||||||
private const decimal _ticksPerMicrosecond = TimeSpan.TicksPerMillisecond / 1000m;
|
private const double _ticksPerMicrosecond = TimeSpan.TicksPerMillisecond / 1000d;
|
||||||
private const decimal _ticksPerNanosecond = TimeSpan.TicksPerMillisecond / 1000m / 1000;
|
private const double _ticksPerNanosecond = TimeSpan.TicksPerMillisecond / 1000d / 1000;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override bool CanConvert(Type typeToConvert)
|
public override bool CanConvert(Type typeToConvert)
|
||||||
@@ -35,22 +34,22 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
|
|||||||
public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||||
=> (T)((object?)ReadDateTime(ref reader, typeToConvert, options) ?? default(T))!;
|
=> (T)((object?)ReadDateTime(ref reader, typeToConvert, options) ?? default(T))!;
|
||||||
|
|
||||||
private DateTime? ReadDateTime(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
private static DateTime? ReadDateTime(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||||
{
|
{
|
||||||
if (reader.TokenType == JsonTokenType.Null)
|
if (reader.TokenType == JsonTokenType.Null)
|
||||||
{
|
{
|
||||||
if (typeToConvert == typeof(DateTime))
|
if (typeToConvert == typeof(DateTime))
|
||||||
LibraryHelpers.StaticLogger?.LogWarning("DateTime value of null, but property is not nullable");
|
Trace.WriteLine($"{DateTime.Now:yyyy/MM/dd HH:mm:ss:fff} | Warning | DateTime value of null, but property is not nullable");
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reader.TokenType is JsonTokenType.Number)
|
if (reader.TokenType is JsonTokenType.Number)
|
||||||
{
|
{
|
||||||
var decValue = reader.GetDecimal();
|
var longValue = reader.GetDouble();
|
||||||
if (decValue == 0 || decValue < 0)
|
if (longValue == 0 || longValue < 0)
|
||||||
return default;
|
return default;
|
||||||
|
|
||||||
return ParseFromDecimal(decValue);
|
return ParseFromDouble(longValue);
|
||||||
}
|
}
|
||||||
else if (reader.TokenType is JsonTokenType.String)
|
else if (reader.TokenType is JsonTokenType.String)
|
||||||
{
|
{
|
||||||
@@ -58,7 +57,7 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
|
|||||||
if (string.IsNullOrWhiteSpace(stringValue)
|
if (string.IsNullOrWhiteSpace(stringValue)
|
||||||
|| stringValue == "-1"
|
|| stringValue == "-1"
|
||||||
|| stringValue == "0001-01-01T00:00:00Z"
|
|| stringValue == "0001-01-01T00:00:00Z"
|
||||||
|| decimal.TryParse(stringValue, out var decVal) && decVal == 0)
|
|| double.TryParse(stringValue, out var doubleVal) && doubleVal == 0)
|
||||||
{
|
{
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
@@ -89,24 +88,20 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Parse a double value to datetime
|
/// Parse a long value to datetime
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static DateTime ParseFromDouble(double value)
|
/// <param name="longValue"></param>
|
||||||
=> ParseFromDecimal((decimal)value);
|
/// <returns></returns>
|
||||||
|
public static DateTime ParseFromDouble(double longValue)
|
||||||
/// <summary>
|
|
||||||
/// Parse a decimal value to datetime
|
|
||||||
/// </summary>
|
|
||||||
public static DateTime ParseFromDecimal(decimal value)
|
|
||||||
{
|
{
|
||||||
if (value < 19999999999)
|
if (longValue < 19999999999)
|
||||||
return ConvertFromSeconds(value);
|
return ConvertFromSeconds(longValue);
|
||||||
if (value < 19999999999999)
|
if (longValue < 19999999999999)
|
||||||
return ConvertFromMilliseconds(value);
|
return ConvertFromMilliseconds(longValue);
|
||||||
if (value < 19999999999999999)
|
if (longValue < 19999999999999999)
|
||||||
return ConvertFromMicroseconds(value);
|
return ConvertFromMicroseconds(longValue);
|
||||||
|
|
||||||
return ConvertFromNanoseconds(value);
|
return ConvertFromNanoseconds(longValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -125,7 +120,7 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
|
|||||||
|| !int.TryParse(stringValue.Substring(8, 2), out var hour)
|
|| !int.TryParse(stringValue.Substring(8, 2), out var hour)
|
||||||
|| !int.TryParse(stringValue.Substring(10, 2), out var minute))
|
|| !int.TryParse(stringValue.Substring(10, 2), out var minute))
|
||||||
{
|
{
|
||||||
LibraryHelpers.StaticLogger?.LogWarning("Unknown DateTime format: " + stringValue);
|
Trace.WriteLine($"{DateTime.Now:yyyy/MM/dd HH:mm:ss:fff} | Warning | Unknown DateTime format: " + stringValue);
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
return new DateTime(year, month, day, hour, minute, 0, DateTimeKind.Utc);
|
return new DateTime(year, month, day, hour, minute, 0, DateTimeKind.Utc);
|
||||||
@@ -138,7 +133,7 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
|
|||||||
|| !int.TryParse(stringValue.Substring(4, 2), out var month)
|
|| !int.TryParse(stringValue.Substring(4, 2), out var month)
|
||||||
|| !int.TryParse(stringValue.Substring(6, 2), out var day))
|
|| !int.TryParse(stringValue.Substring(6, 2), out var day))
|
||||||
{
|
{
|
||||||
LibraryHelpers.StaticLogger?.LogWarning("Unknown DateTime format: " + stringValue);
|
Trace.WriteLine($"{DateTime.Now:yyyy/MM/dd HH:mm:ss:fff} | Warning | Unknown DateTime format: " + stringValue);
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
return new DateTime(year, month, day, 0, 0, 0, DateTimeKind.Utc);
|
return new DateTime(year, month, day, 0, 0, 0, DateTimeKind.Utc);
|
||||||
@@ -151,25 +146,25 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
|
|||||||
|| !int.TryParse(stringValue.Substring(2, 2), out var month)
|
|| !int.TryParse(stringValue.Substring(2, 2), out var month)
|
||||||
|| !int.TryParse(stringValue.Substring(4, 2), out var day))
|
|| !int.TryParse(stringValue.Substring(4, 2), out var day))
|
||||||
{
|
{
|
||||||
LibraryHelpers.StaticLogger?.LogWarning("Unknown DateTime format: " + stringValue);
|
Trace.WriteLine("{DateTime.Now:yyyy/MM/dd HH:mm:ss:fff} | Warning | Unknown DateTime format: " + stringValue);
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
return new DateTime(year + 2000, month, day, 0, 0, 0, DateTimeKind.Utc);
|
return new DateTime(year + 2000, month, day, 0, 0, 0, DateTimeKind.Utc);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (decimal.TryParse(stringValue, NumberStyles.Float, CultureInfo.InvariantCulture, out var decimalValue))
|
if (double.TryParse(stringValue, NumberStyles.Float, CultureInfo.InvariantCulture, out var doubleValue))
|
||||||
{
|
{
|
||||||
// Parse 1637745563.000 format
|
// Parse 1637745563.000 format
|
||||||
if (decimalValue <= 0)
|
if (doubleValue <= 0)
|
||||||
return default;
|
return default;
|
||||||
if (decimalValue < 19999999999)
|
if (doubleValue < 19999999999)
|
||||||
return ConvertFromSeconds(decimalValue);
|
return ConvertFromSeconds(doubleValue);
|
||||||
if (decimalValue < 19999999999999)
|
if (doubleValue < 19999999999999)
|
||||||
return ConvertFromMilliseconds(decimalValue);
|
return ConvertFromMilliseconds((long)doubleValue);
|
||||||
if (decimalValue < 19999999999999999)
|
if (doubleValue < 19999999999999999)
|
||||||
return ConvertFromMicroseconds(decimalValue);
|
return ConvertFromMicroseconds((long)doubleValue);
|
||||||
|
|
||||||
return ConvertFromNanoseconds(decimalValue);
|
return ConvertFromNanoseconds((long)doubleValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stringValue.Length == 10)
|
if (stringValue.Length == 10)
|
||||||
@@ -180,7 +175,7 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
|
|||||||
|| !int.TryParse(values[1], out var month)
|
|| !int.TryParse(values[1], out var month)
|
||||||
|| !int.TryParse(values[2], out var day))
|
|| !int.TryParse(values[2], out var day))
|
||||||
{
|
{
|
||||||
LibraryHelpers.StaticLogger?.LogWarning("Unknown DateTime format: " + stringValue);
|
Trace.WriteLine("{DateTime.Now:yyyy/MM/dd HH:mm:ss:fff} | Warning | Unknown DateTime format: " + stringValue);
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,71 +188,54 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Convert a seconds since epoch (01-01-1970) value to DateTime
|
/// Convert a seconds since epoch (01-01-1970) value to DateTime
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static DateTime ConvertFromSeconds(decimal seconds) => _epoch.AddTicks((long)Math.Round(seconds * _ticksPerSecond));
|
/// <param name="seconds"></param>
|
||||||
/// <summary>
|
/// <returns></returns>
|
||||||
/// Convert a nanoseconds since epoch (01-01-1970) value to DateTime
|
public static DateTime ConvertFromSeconds(double seconds) => _epoch.AddTicks((long)Math.Round(seconds * _ticksPerSecond));
|
||||||
/// </summary>
|
|
||||||
public static DateTime ConvertFromSeconds(double seconds) => ConvertFromSeconds((decimal)seconds);
|
|
||||||
/// <summary>
|
|
||||||
/// Convert a nanoseconds since epoch (01-01-1970) value to DateTime
|
|
||||||
/// </summary>
|
|
||||||
public static DateTime ConvertFromSeconds(long seconds) => ConvertFromSeconds((decimal)seconds);
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Convert a milliseconds since epoch (01-01-1970) value to DateTime
|
/// Convert a milliseconds since epoch (01-01-1970) value to DateTime
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static DateTime ConvertFromMilliseconds(decimal milliseconds) => _epoch.AddTicks((long)Math.Round(milliseconds * TimeSpan.TicksPerMillisecond));
|
/// <param name="milliseconds"></param>
|
||||||
/// <summary>
|
/// <returns></returns>
|
||||||
/// Convert a nanoseconds since epoch (01-01-1970) value to DateTime
|
public static DateTime ConvertFromMilliseconds(double milliseconds) => _epoch.AddTicks((long)Math.Round(milliseconds * TimeSpan.TicksPerMillisecond));
|
||||||
/// </summary>
|
|
||||||
public static DateTime ConvertFromMilliseconds(double milliseconds) => ConvertFromMilliseconds((decimal)milliseconds);
|
|
||||||
/// <summary>
|
|
||||||
/// Convert a nanoseconds since epoch (01-01-1970) value to DateTime
|
|
||||||
/// </summary>
|
|
||||||
public static DateTime ConvertFromMilliseconds(long milliseconds) => ConvertFromMilliseconds((decimal)milliseconds);
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Convert a microseconds since epoch (01-01-1970) value to DateTime
|
/// Convert a microseconds since epoch (01-01-1970) value to DateTime
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static DateTime ConvertFromMicroseconds(decimal microseconds) => _epoch.AddTicks((long)Math.Round(microseconds * _ticksPerMicrosecond));
|
/// <param name="microseconds"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static DateTime ConvertFromMicroseconds(double microseconds) => _epoch.AddTicks((long)Math.Round(microseconds * _ticksPerMicrosecond));
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Convert a nanoseconds since epoch (01-01-1970) value to DateTime
|
/// Convert a nanoseconds since epoch (01-01-1970) value to DateTime
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static DateTime ConvertFromMicroseconds(double microseconds) => ConvertFromMicroseconds((decimal)microseconds);
|
/// <param name="nanoseconds"></param>
|
||||||
/// <summary>
|
/// <returns></returns>
|
||||||
/// Convert a nanoseconds since epoch (01-01-1970) value to DateTime
|
public static DateTime ConvertFromNanoseconds(double nanoseconds) => _epoch.AddTicks((long)Math.Round(nanoseconds * _ticksPerNanosecond));
|
||||||
/// </summary>
|
|
||||||
public static DateTime ConvertFromMicroseconds(long microseconds) => ConvertFromMicroseconds((decimal)microseconds);
|
|
||||||
/// <summary>
|
|
||||||
/// Convert a nanoseconds since epoch (01-01-1970) value to DateTime
|
|
||||||
/// </summary>
|
|
||||||
public static DateTime ConvertFromNanoseconds(decimal nanoseconds) => _epoch.AddTicks((long)Math.Round(nanoseconds * _ticksPerNanosecond));
|
|
||||||
/// <summary>
|
|
||||||
/// Convert a nanoseconds since epoch (01-01-1970) value to DateTime
|
|
||||||
/// </summary>
|
|
||||||
public static DateTime ConvertFromNanoseconds(double nanoseconds) => ConvertFromNanoseconds((decimal)nanoseconds);
|
|
||||||
/// <summary>
|
|
||||||
/// Convert a nanoseconds since epoch (01-01-1970) value to DateTime
|
|
||||||
/// </summary>
|
|
||||||
public static DateTime ConvertFromNanoseconds(long nanoseconds) => ConvertFromNanoseconds((decimal)nanoseconds);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Convert a DateTime value to seconds since epoch (01-01-1970) value
|
/// Convert a DateTime value to seconds since epoch (01-01-1970) value
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="time"></param>
|
||||||
|
/// <returns></returns>
|
||||||
[return: NotNullIfNotNull("time")]
|
[return: NotNullIfNotNull("time")]
|
||||||
public static long? ConvertToSeconds(DateTime? time) => time == null ? null : (long)Math.Round((time.Value - _epoch).TotalSeconds);
|
public static long? ConvertToSeconds(DateTime? time) => time == null ? null : (long)Math.Round((time.Value - _epoch).TotalSeconds);
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Convert a DateTime value to milliseconds since epoch (01-01-1970) value
|
/// Convert a DateTime value to milliseconds since epoch (01-01-1970) value
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="time"></param>
|
||||||
|
/// <returns></returns>
|
||||||
[return: NotNullIfNotNull("time")]
|
[return: NotNullIfNotNull("time")]
|
||||||
public static long? ConvertToMilliseconds(DateTime? time) => time == null ? null : (long)Math.Round((time.Value - _epoch).TotalMilliseconds);
|
public static long? ConvertToMilliseconds(DateTime? time) => time == null ? null : (long)Math.Round((time.Value - _epoch).TotalMilliseconds);
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Convert a DateTime value to microseconds since epoch (01-01-1970) value
|
/// Convert a DateTime value to microseconds since epoch (01-01-1970) value
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="time"></param>
|
||||||
|
/// <returns></returns>
|
||||||
[return: NotNullIfNotNull("time")]
|
[return: NotNullIfNotNull("time")]
|
||||||
public static long? ConvertToMicroseconds(DateTime? time) => time == null ? null : (long)Math.Round((time.Value - _epoch).Ticks / _ticksPerMicrosecond);
|
public static long? ConvertToMicroseconds(DateTime? time) => time == null ? null : (long)Math.Round((time.Value - _epoch).Ticks / _ticksPerMicrosecond);
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Convert a DateTime value to nanoseconds since epoch (01-01-1970) value
|
/// Convert a DateTime value to nanoseconds since epoch (01-01-1970) value
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="time"></param>
|
||||||
|
/// <returns></returns>
|
||||||
[return: NotNullIfNotNull("time")]
|
[return: NotNullIfNotNull("time")]
|
||||||
public static long? ConvertToNanoseconds(DateTime? time) => time == null ? null : (long)Math.Round((time.Value - _epoch).Ticks / _ticksPerNanosecond);
|
public static long? ConvertToNanoseconds(DateTime? time) => time == null ? null : (long)Math.Round((time.Value - _epoch).Ticks / _ticksPerNanosecond);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,14 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Globalization;
|
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Converters.SystemTextJson
|
namespace CryptoExchange.Net.Converters.SystemTextJson;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Decimal converter
|
||||||
|
/// </summary>
|
||||||
|
public class DecimalConverter : JsonConverter<decimal?>
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Decimal converter
|
|
||||||
/// </summary>
|
|
||||||
public class DecimalConverter : JsonConverter<decimal?>
|
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override decimal? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
public override decimal? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||||
{
|
{
|
||||||
@@ -41,5 +40,4 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
|
|||||||
else
|
else
|
||||||
writer.WriteNumberValue(value.Value);
|
writer.WriteNumberValue(value.Value);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Converters.SystemTextJson
|
namespace CryptoExchange.Net.Converters.SystemTextJson;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converter for serializing decimal values as string
|
||||||
|
/// </summary>
|
||||||
|
public class DecimalStringWriterConverter : JsonConverter<decimal>
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Converter for serializing decimal values as string
|
|
||||||
/// </summary>
|
|
||||||
public class DecimalStringWriterConverter : JsonConverter<decimal>
|
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override decimal Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
public override decimal Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||||
{
|
{
|
||||||
@@ -19,5 +19,4 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Write(Utf8JsonWriter writer, decimal value, JsonSerializerOptions options)
|
public override void Write(Utf8JsonWriter writer, decimal value, JsonSerializerOptions options)
|
||||||
=> writer.WriteStringValue(value.ToString(CultureInfo.InvariantCulture) ?? null);
|
=> writer.WriteStringValue(value.ToString(CultureInfo.InvariantCulture) ?? null);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
using CryptoExchange.Net.Attributes;
|
using CryptoExchange.Net.Attributes;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using Microsoft.Extensions.Logging.Abstractions;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@@ -11,13 +9,13 @@ using System.Reflection;
|
|||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Converters.SystemTextJson
|
namespace CryptoExchange.Net.Converters.SystemTextJson;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Static EnumConverter methods
|
||||||
|
/// </summary>
|
||||||
|
public static class EnumConverter
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Static EnumConverter methods
|
|
||||||
/// </summary>
|
|
||||||
public static class EnumConverter
|
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get the enum value from a string
|
/// Get the enum value from a string
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -54,20 +52,20 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
|
|||||||
public static string? GetString<T>(T? enumValue) where T : struct, Enum
|
public static string? GetString<T>(T? enumValue) where T : struct, Enum
|
||||||
#endif
|
#endif
|
||||||
=> EnumConverter<T>.GetString(enumValue);
|
=> EnumConverter<T>.GetString(enumValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Converter for enum values. Enums entries should be noted with a MapAttribute to map the enum value to a string value
|
/// Converter for enum values. Enums entries should be noted with a MapAttribute to map the enum value to a string value
|
||||||
/// </summary>
|
/// </summary>
|
||||||
#if NET5_0_OR_GREATER
|
#if NET5_0_OR_GREATER
|
||||||
public class EnumConverter<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor | DynamicallyAccessedMemberTypes.PublicFields)] T>
|
public class EnumConverter<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor | DynamicallyAccessedMemberTypes.PublicFields)] T>
|
||||||
#else
|
#else
|
||||||
public class EnumConverter<T>
|
public class EnumConverter<T>
|
||||||
#endif
|
#endif
|
||||||
: JsonConverter<T>, INullableConverterFactory where T : struct, Enum
|
: JsonConverter<T>, INullableConverterFactory where T : struct, Enum
|
||||||
{
|
{
|
||||||
private static List<KeyValuePair<T, string>>? _mapping = null;
|
private static List<KeyValuePair<T, string>>? _mapping;
|
||||||
private NullableEnumConverter? _nullableEnumConverter = null;
|
private NullableEnumConverter? _nullableEnumConverter;
|
||||||
|
|
||||||
private static ConcurrentBag<string> _unknownValuesWarned = new ConcurrentBag<string>();
|
private static ConcurrentBag<string> _unknownValuesWarned = new ConcurrentBag<string>();
|
||||||
|
|
||||||
@@ -81,7 +79,7 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
|
|||||||
}
|
}
|
||||||
public override T? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
public override T? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||||
{
|
{
|
||||||
return _enumConverter.ReadNullable(ref reader, typeToConvert, options, out var isEmptyString);
|
return EnumConverter<T>.ReadNullable(ref reader, typeToConvert, options, out var isEmptyString, out var warn);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Write(Utf8JsonWriter writer, T? value, JsonSerializerOptions options)
|
public override void Write(Utf8JsonWriter writer, T? value, JsonSerializerOptions options)
|
||||||
@@ -100,13 +98,20 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||||
{
|
{
|
||||||
var t = ReadNullable(ref reader, typeToConvert, options, out var isEmptyString);
|
var t = ReadNullable(ref reader, typeToConvert, options, out var isEmptyString, out var warn);
|
||||||
if (t == null)
|
if (t == null)
|
||||||
{
|
{
|
||||||
if (isEmptyString && !_unknownValuesWarned.Contains(null))
|
if (warn)
|
||||||
|
{
|
||||||
|
if (isEmptyString)
|
||||||
{
|
{
|
||||||
// We received an empty string and have no mapping for it, and the property isn't nullable
|
// We received an empty string and have no mapping for it, and the property isn't nullable
|
||||||
LibraryHelpers.StaticLogger?.LogWarning($"Received null or empty enum value, but property type is not a nullable enum. EnumType: {typeof(T).FullName}. If you think {typeof(T).FullName} should be nullable please open an issue on the Github repo");
|
Trace.WriteLine($"{DateTime.Now:yyyy/MM/dd HH:mm:ss:fff} | Warning | Received empty string as enum value, but property type is not a nullable enum. EnumType: {typeof(T).Name}. If you think {typeof(T).Name} should be nullable please open an issue on the Github repo");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Trace.WriteLine($"{DateTime.Now:yyyy/MM/dd HH:mm:ss:fff} | Warning | Received null enum value, but property type is not a nullable enum. EnumType: {typeof(T).Name}. If you think {typeof(T).Name} should be nullable please open an issue on the Github repo");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new T(); // return default value
|
return new T(); // return default value
|
||||||
@@ -117,9 +122,10 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private T? ReadNullable(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options, out bool isEmptyString)
|
private static T? ReadNullable(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options, out bool isEmptyString, out bool warn)
|
||||||
{
|
{
|
||||||
isEmptyString = false;
|
isEmptyString = false;
|
||||||
|
warn = false;
|
||||||
var enumType = typeof(T);
|
var enumType = typeof(T);
|
||||||
if (_mapping == null)
|
if (_mapping == null)
|
||||||
_mapping = AddMapping();
|
_mapping = AddMapping();
|
||||||
@@ -134,10 +140,10 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
|
|||||||
_ => throw new Exception("Invalid token type for enum deserialization: " + reader.TokenType)
|
_ => throw new Exception("Invalid token type for enum deserialization: " + reader.TokenType)
|
||||||
};
|
};
|
||||||
|
|
||||||
if (stringValue is null)
|
if (string.IsNullOrEmpty(stringValue))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
if (!GetValue(enumType, stringValue, out var result))
|
if (!GetValue(enumType, stringValue!, out var result))
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(stringValue))
|
if (string.IsNullOrWhiteSpace(stringValue))
|
||||||
{
|
{
|
||||||
@@ -148,8 +154,9 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
|
|||||||
// We received an enum value but weren't able to parse it.
|
// We received an enum value but weren't able to parse it.
|
||||||
if (!_unknownValuesWarned.Contains(stringValue))
|
if (!_unknownValuesWarned.Contains(stringValue))
|
||||||
{
|
{
|
||||||
|
warn = true;
|
||||||
_unknownValuesWarned.Add(stringValue!);
|
_unknownValuesWarned.Add(stringValue!);
|
||||||
LibraryHelpers.StaticLogger?.LogWarning($"Cannot map enum value. EnumType: {enumType.FullName}, Value: {stringValue}, Known values: {string.Join(", ", _mapping.Select(m => m.Value))}. If you think {stringValue} should added please open an issue on the Github repo");
|
Trace.WriteLine($"{DateTime.Now:yyyy/MM/dd HH:mm:ss:fff} | Warning | Cannot map enum value. EnumType: {enumType.Name}, Value: {stringValue}, Known values: {string.Join(", ", _mapping.Select(m => m.Value))}. If you think {stringValue} should added please open an issue on the Github repo");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,13 +204,6 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (String.IsNullOrEmpty(value))
|
|
||||||
{
|
|
||||||
// An empty/null value will always fail when parsing, so just return here
|
|
||||||
result = default;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// If no explicit mapping is found try to parse string
|
// If no explicit mapping is found try to parse string
|
||||||
@@ -285,5 +285,4 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
|
|||||||
_nullableEnumConverter ??= new NullableEnumConverter(this);
|
_nullableEnumConverter ??= new NullableEnumConverter(this);
|
||||||
return _nullableEnumConverter;
|
return _nullableEnumConverter;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,14 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Globalization;
|
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Converters.SystemTextJson
|
namespace CryptoExchange.Net.Converters.SystemTextJson;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converter for serializing enum values as int
|
||||||
|
/// </summary>
|
||||||
|
public class EnumIntWriterConverter<T> : JsonConverter<T> where T: struct, Enum
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Converter for serializing enum values as int
|
|
||||||
/// </summary>
|
|
||||||
public class EnumIntWriterConverter<T> : JsonConverter<T> where T: struct, Enum
|
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||||
{
|
{
|
||||||
@@ -19,5 +18,4 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options)
|
public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options)
|
||||||
=> writer.WriteNumberValue((int)(object)value);
|
=> writer.WriteNumberValue((int)(object)value);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Converters.SystemTextJson
|
namespace CryptoExchange.Net.Converters.SystemTextJson;
|
||||||
|
|
||||||
|
internal interface INullableConverterFactory
|
||||||
{
|
{
|
||||||
internal interface INullableConverterFactory
|
|
||||||
{
|
|
||||||
JsonConverter CreateNullableConverter();
|
JsonConverter CreateNullableConverter();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Converters.SystemTextJson
|
namespace CryptoExchange.Net.Converters.SystemTextJson;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Int converter
|
||||||
|
/// </summary>
|
||||||
|
public class IntConverter : JsonConverter<int?>
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Int converter
|
|
||||||
/// </summary>
|
|
||||||
public class IntConverter : JsonConverter<int?>
|
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override int? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
public override int? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||||
{
|
{
|
||||||
@@ -36,5 +36,4 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
|
|||||||
else
|
else
|
||||||
writer.WriteNumberValue(value.Value);
|
writer.WriteNumberValue(value.Value);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Converters.SystemTextJson
|
namespace CryptoExchange.Net.Converters.SystemTextJson;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Int converter
|
||||||
|
/// </summary>
|
||||||
|
public class LongConverter : JsonConverter<long?>
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Int converter
|
|
||||||
/// </summary>
|
|
||||||
public class LongConverter : JsonConverter<long?>
|
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override long? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
public override long? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||||
{
|
{
|
||||||
@@ -36,5 +36,4 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
|
|||||||
else
|
else
|
||||||
writer.WriteNumberValue(value.Value);
|
writer.WriteNumberValue(value.Value);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,12 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
using System.Text.Json.Serialization.Metadata;
|
using System.Text.Json.Serialization.Metadata;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Converters.SystemTextJson
|
namespace CryptoExchange.Net.Converters.SystemTextJson;
|
||||||
|
|
||||||
|
internal class NullableEnumConverterFactory : JsonConverterFactory
|
||||||
{
|
{
|
||||||
internal class NullableEnumConverterFactory : JsonConverterFactory
|
|
||||||
{
|
|
||||||
private readonly IJsonTypeInfoResolver _jsonTypeInfoResolver;
|
private readonly IJsonTypeInfoResolver _jsonTypeInfoResolver;
|
||||||
private static readonly JsonSerializerOptions _options = new JsonSerializerOptions();
|
private static readonly JsonSerializerOptions _options = new JsonSerializerOptions();
|
||||||
|
|
||||||
@@ -39,5 +37,4 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
|
|||||||
|
|
||||||
return nullConverterFactory.CreateNullableConverter();
|
return nullConverterFactory.CreateNullableConverter();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Converters.SystemTextJson
|
namespace CryptoExchange.Net.Converters.SystemTextJson;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Read string or number as string
|
||||||
|
/// </summary>
|
||||||
|
public class NumberStringConverter : JsonConverter<string?>
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Read string or number as string
|
|
||||||
/// </summary>
|
|
||||||
public class NumberStringConverter : JsonConverter<string?>
|
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override string? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
public override string? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||||
{
|
{
|
||||||
@@ -38,5 +38,4 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
|
|||||||
{
|
{
|
||||||
writer.WriteStringValue(value);
|
writer.WriteStringValue(value);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,17 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
|
#if NET5_0_OR_GREATER
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Converters.SystemTextJson
|
namespace CryptoExchange.Net.Converters.SystemTextJson;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converter for values which contain a nested json value
|
||||||
|
/// </summary>
|
||||||
|
public class ObjectStringConverter<T> : JsonConverter<T>
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Converter for values which contain a nested json value
|
|
||||||
/// </summary>
|
|
||||||
public class ObjectStringConverter<T> : JsonConverter<T>
|
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
#if NET5_0_OR_GREATER
|
#if NET5_0_OR_GREATER
|
||||||
[UnconditionalSuppressMessage("AssemblyLoadTrimming", "IL3050:RequiresUnreferencedCode", Justification = "JsonSerializerOptions provided here has TypeInfoResolver set")]
|
[UnconditionalSuppressMessage("AssemblyLoadTrimming", "IL3050:RequiresUnreferencedCode", Justification = "JsonSerializerOptions provided here has TypeInfoResolver set")]
|
||||||
@@ -24,7 +26,7 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
|
|||||||
if (string.IsNullOrEmpty(value))
|
if (string.IsNullOrEmpty(value))
|
||||||
return default;
|
return default;
|
||||||
|
|
||||||
return (T?)JsonDocument.Parse(value!).Deserialize(typeof(T), options);
|
return JsonDocument.Parse(value!).Deserialize<T>(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -39,5 +41,4 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
|
|||||||
|
|
||||||
writer.WriteStringValue(JsonSerializer.Serialize(value, options));
|
writer.WriteStringValue(JsonSerializer.Serialize(value, options));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Converters.SystemTextJson
|
namespace CryptoExchange.Net.Converters.SystemTextJson;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Replace a value on a string property
|
||||||
|
/// </summary>
|
||||||
|
public abstract class ReplaceConverter : JsonConverter<string>
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Replace a value on a string property
|
|
||||||
/// </summary>
|
|
||||||
public abstract class ReplaceConverter : JsonConverter<string>
|
|
||||||
{
|
|
||||||
private readonly (string ValueToReplace, string ValueToReplaceWith)[] _replacementSets;
|
private readonly (string ValueToReplace, string ValueToReplaceWith)[] _replacementSets;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -19,7 +19,7 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
|
|||||||
{
|
{
|
||||||
_replacementSets = replaceSets.Select(x =>
|
_replacementSets = replaceSets.Select(x =>
|
||||||
{
|
{
|
||||||
var split = x.Split(new string[] { "->" }, StringSplitOptions.None);
|
var split = x.Split(["->"], StringSplitOptions.None);
|
||||||
if (split.Length != 2)
|
if (split.Length != 2)
|
||||||
throw new ArgumentException("Invalid replacement config");
|
throw new ArgumentException("Invalid replacement config");
|
||||||
return (split[0], split[1]);
|
return (split[0], split[1]);
|
||||||
@@ -37,5 +37,4 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
|
|||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options) => writer.WriteStringValue(value);
|
public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options) => writer.WriteStringValue(value);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,13 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Converters.SystemTextJson
|
namespace CryptoExchange.Net.Converters.SystemTextJson;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Attribute to mark a model as json serializable. Used for AOT compilation.
|
||||||
|
/// </summary>
|
||||||
|
[AttributeUsage(System.AttributeTargets.Class | AttributeTargets.Enum | System.AttributeTargets.Interface)]
|
||||||
|
public class SerializationModelAttribute : Attribute
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Attribute to mark a model as json serializable. Used for AOT compilation.
|
|
||||||
/// </summary>
|
|
||||||
[AttributeUsage(System.AttributeTargets.Class | AttributeTargets.Enum | System.AttributeTargets.Interface)]
|
|
||||||
public class SerializationModelAttribute : Attribute
|
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// ctor
|
/// ctor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -19,5 +17,4 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="type"></param>
|
/// <param name="type"></param>
|
||||||
public SerializationModelAttribute(Type type) { }
|
public SerializationModelAttribute(Type type) { }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Converters.SystemTextJson
|
namespace CryptoExchange.Net.Converters.SystemTextJson;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Serializer options
|
||||||
|
/// </summary>
|
||||||
|
public static class SerializerOptions
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Serializer options
|
|
||||||
/// </summary>
|
|
||||||
public static class SerializerOptions
|
|
||||||
{
|
|
||||||
private static readonly ConcurrentDictionary<JsonSerializerContext, JsonSerializerOptions> _cache = new ConcurrentDictionary<JsonSerializerContext, JsonSerializerOptions>();
|
private static readonly ConcurrentDictionary<JsonSerializerContext, JsonSerializerOptions> _cache = new ConcurrentDictionary<JsonSerializerContext, JsonSerializerOptions>();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -43,5 +43,4 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
|
|||||||
|
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,15 @@
|
|||||||
using CryptoExchange.Net.SharedApis;
|
using CryptoExchange.Net.SharedApis;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Converters.SystemTextJson
|
namespace CryptoExchange.Net.Converters.SystemTextJson;
|
||||||
{
|
|
||||||
internal class SharedQuantityConverter : SharedQuantityReferenceConverter<SharedQuantity> { }
|
|
||||||
internal class SharedOrderQuantityConverter : SharedQuantityReferenceConverter<SharedOrderQuantity> { }
|
|
||||||
|
|
||||||
internal class SharedQuantityReferenceConverter<T> : JsonConverter<T> where T: SharedQuantityReference, new()
|
internal class SharedQuantityConverter : SharedQuantityReferenceConverter<SharedQuantity> { }
|
||||||
{
|
internal class SharedOrderQuantityConverter : SharedQuantityReferenceConverter<SharedOrderQuantity> { }
|
||||||
|
|
||||||
|
internal class SharedQuantityReferenceConverter<T> : JsonConverter<T> where T: SharedQuantityReference, new()
|
||||||
|
{
|
||||||
public override T? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
public override T? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||||
{
|
{
|
||||||
if (reader.TokenType != JsonTokenType.StartArray)
|
if (reader.TokenType != JsonTokenType.StartArray)
|
||||||
@@ -56,5 +54,4 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
|
|||||||
writer.WriteNumberValue(value.QuantityInContracts.Value);
|
writer.WriteNumberValue(value.QuantityInContracts.Value);
|
||||||
writer.WriteEndArray();
|
writer.WriteEndArray();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,12 @@
|
|||||||
using CryptoExchange.Net.SharedApis;
|
using CryptoExchange.Net.SharedApis;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Converters.SystemTextJson
|
namespace CryptoExchange.Net.Converters.SystemTextJson;
|
||||||
|
|
||||||
|
internal class SharedSymbolConverter : JsonConverter<SharedSymbol>
|
||||||
{
|
{
|
||||||
internal class SharedSymbolConverter : JsonConverter<SharedSymbol>
|
|
||||||
{
|
|
||||||
public override SharedSymbol? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
public override SharedSymbol? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||||
{
|
{
|
||||||
if (reader.TokenType != JsonTokenType.StartArray)
|
if (reader.TokenType != JsonTokenType.StartArray)
|
||||||
@@ -42,5 +40,4 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
|
|||||||
writer.WriteStringValue(value.DeliverTime?.ToString());
|
writer.WriteStringValue(value.DeliverTime?.ToString());
|
||||||
writer.WriteEndArray();
|
writer.WriteEndArray();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,22 @@
|
|||||||
using CryptoExchange.Net.Converters.MessageParsing;
|
using CryptoExchange.Net.Converters.MessageParsing;
|
||||||
using CryptoExchange.Net.Interfaces;
|
using CryptoExchange.Net.Interfaces;
|
||||||
using CryptoExchange.Net.Objects;
|
using CryptoExchange.Net.Objects;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
#if NET5_0_OR_GREATER
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
#endif
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Converters.SystemTextJson
|
namespace CryptoExchange.Net.Converters.SystemTextJson;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// System.Text.Json message accessor
|
||||||
|
/// </summary>
|
||||||
|
public abstract class SystemTextJsonMessageAccessor : IMessageAccessor
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// System.Text.Json message accessor
|
|
||||||
/// </summary>
|
|
||||||
public abstract class SystemTextJsonMessageAccessor : IMessageAccessor
|
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The JsonDocument loaded
|
/// The JsonDocument loaded
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -235,13 +236,15 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
|
|||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public abstract void Clear();
|
public abstract void Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// System.Text.Json stream message accessor
|
/// System.Text.Json stream message accessor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class SystemTextJsonStreamMessageAccessor : SystemTextJsonMessageAccessor, IStreamMessageAccessor
|
#pragma warning disable CA1001 // Types that own disposable fields should be disposable
|
||||||
{
|
public class SystemTextJsonStreamMessageAccessor : SystemTextJsonMessageAccessor, IStreamMessageAccessor
|
||||||
|
#pragma warning restore CA1001 // Types that own disposable fields should be disposable
|
||||||
|
{
|
||||||
private Stream? _stream;
|
private Stream? _stream;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -308,13 +311,13 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
|
|||||||
_document = null;
|
_document = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// System.Text.Json byte message accessor
|
/// System.Text.Json byte message accessor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class SystemTextJsonByteMessageAccessor : SystemTextJsonMessageAccessor, IByteMessageAccessor
|
public class SystemTextJsonByteMessageAccessor : SystemTextJsonMessageAccessor, IByteMessageAccessor
|
||||||
{
|
{
|
||||||
private ReadOnlyMemory<byte> _bytes;
|
private ReadOnlyMemory<byte> _bytes;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -370,5 +373,4 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
|
|||||||
_document?.Dispose();
|
_document?.Dispose();
|
||||||
_document = null;
|
_document = null;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
using CryptoExchange.Net.Interfaces;
|
using CryptoExchange.Net.Interfaces;
|
||||||
|
#if NET5_0_OR_GREATER
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
#endif
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
using System.Text.Json.Serialization.Metadata;
|
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Converters.SystemTextJson
|
namespace CryptoExchange.Net.Converters.SystemTextJson;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public class SystemTextJsonMessageSerializer : IStringMessageSerializer
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
|
||||||
public class SystemTextJsonMessageSerializer : IStringMessageSerializer
|
|
||||||
{
|
|
||||||
private readonly JsonSerializerOptions _options;
|
private readonly JsonSerializerOptions _options;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -25,5 +25,4 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
|
|||||||
[UnconditionalSuppressMessage("AssemblyLoadTrimming", "IL3050:RequiresUnreferencedCode", Justification = "Everything referenced in the loaded assembly is manually preserved, so it's safe")]
|
[UnconditionalSuppressMessage("AssemblyLoadTrimming", "IL3050:RequiresUnreferencedCode", Justification = "Everything referenced in the loaded assembly is manually preserved, so it's safe")]
|
||||||
#endif
|
#endif
|
||||||
public string Serialize<T>(T message) => JsonSerializer.Serialize(message, _options);
|
public string Serialize<T>(T message) => JsonSerializer.Serialize(message, _options);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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>9.13.0</PackageVersion>
|
<PackageVersion>9.6.0</PackageVersion>
|
||||||
<AssemblyVersion>9.13.0</AssemblyVersion>
|
<AssemblyVersion>9.6.0</AssemblyVersion>
|
||||||
<FileVersion>9.13.0</FileVersion>
|
<FileVersion>9.6.0</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;CryptoExchange.Net</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;CryptoExchange.Net</PackageTags>
|
||||||
<RepositoryType>git</RepositoryType>
|
<RepositoryType>git</RepositoryType>
|
||||||
@@ -24,6 +24,7 @@
|
|||||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<None Include="C:\Projects\CryptoExchange.Net\CryptoExchange.Net\.editorconfig" />
|
||||||
<None Include="Icon\icon.png" Pack="true" PackagePath="\" />
|
<None Include="Icon\icon.png" Pack="true" PackagePath="\" />
|
||||||
<None Include="..\README.md" Pack="true" PackagePath="\" />
|
<None Include="..\README.md" Pack="true" PackagePath="\" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
@@ -40,6 +41,12 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<DocumentationFile>CryptoExchange.Net.xml</DocumentationFile>
|
<DocumentationFile>CryptoExchange.Net.xml</DocumentationFile>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<EnableNETAnalyzers>true</EnableNETAnalyzers>
|
||||||
|
<AnalysisMode>Recommended</AnalysisMode>
|
||||||
|
<AnalysisModeGlobalization>None</AnalysisModeGlobalization>
|
||||||
|
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
|
||||||
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="ConfigureAwaitChecker.Analyzer" Version="5.0.0.1">
|
<PackageReference Include="ConfigureAwaitChecker.Analyzer" Version="5.0.0.1">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
@@ -51,11 +58,14 @@
|
|||||||
</PackageReference>
|
</PackageReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="9.0.10" />
|
<PackageReference Include="Microsoft.Extensions.Logging" Version="9.0.6" />
|
||||||
<PackageReference Include="System.Text.Json" Version="9.0.10" />
|
<PackageReference Include="System.Text.Json" Version="9.0.6" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup Label="Transitive Client Packages">
|
<ItemGroup Label="Transitive Client Packages">
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="9.0.10" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="9.0.6" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Http" Version="9.0.10" />
|
<PackageReference Include="Microsoft.Extensions.Http" Version="9.0.6" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<EditorConfigFiles Remove="C:\Projects\CryptoExchange.Net\CryptoExchange.Net\.editorconfig" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
@@ -1,20 +1,22 @@
|
|||||||
using CryptoExchange.Net.Objects;
|
using CryptoExchange.Net.Objects;
|
||||||
using CryptoExchange.Net.SharedApis;
|
using CryptoExchange.Net.SharedApis;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
#if NETSTANDARD2_1_OR_GREATER || NET9_0_OR_GREATER
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
|
#endif
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace CryptoExchange.Net
|
namespace CryptoExchange.Net;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// General helpers functions
|
||||||
|
/// </summary>
|
||||||
|
public static class ExchangeHelpers
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// General helpers functions
|
|
||||||
/// </summary>
|
|
||||||
public static class ExchangeHelpers
|
|
||||||
{
|
|
||||||
private const string _allowedRandomChars = "ABCDEFGHIJKLMONOPQRSTUVWXYZabcdefghijklmonopqrstuvwxyz0123456789";
|
private const string _allowedRandomChars = "ABCDEFGHIJKLMONOPQRSTUVWXYZabcdefghijklmonopqrstuvwxyz0123456789";
|
||||||
private const string _allowedRandomHexChars = "0123456789ABCDEF";
|
private const string _allowedRandomHexChars = "0123456789ABCDEF";
|
||||||
|
|
||||||
@@ -89,6 +91,8 @@ namespace CryptoExchange.Net
|
|||||||
else value += (step.Value - offset);
|
else value += (step.Value - offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
value = RoundDown(value, 8);
|
||||||
|
|
||||||
return value.Normalize();
|
return value.Normalize();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -285,16 +289,16 @@ namespace CryptoExchange.Net
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Execute multiple requests to retrieve multiple pages of the result set
|
/// Execute multiple requests to retrieve multiple pages of the result set
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">Type of the client</typeparam>
|
/// <typeparam name="TResult">Type of the client</typeparam>
|
||||||
/// <typeparam name="U">Type of the request</typeparam>
|
/// <typeparam name="TRequest">Type of the request</typeparam>
|
||||||
/// <param name="paginatedFunc">The func to execute with each request</param>
|
/// <param name="paginatedFunc">The func to execute with each request</param>
|
||||||
/// <param name="request">The request parameters</param>
|
/// <param name="request">The request parameters</param>
|
||||||
/// <param name="ct">Cancellation token</param>
|
/// <param name="ct">Cancellation token</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static async IAsyncEnumerable<ExchangeWebResult<T[]>> ExecutePages<T, U>(Func<U, INextPageToken?, CancellationToken, Task<ExchangeWebResult<T[]>>> paginatedFunc, U request, [EnumeratorCancellation]CancellationToken ct = default)
|
public static async IAsyncEnumerable<ExchangeWebResult<TResult[]>> ExecutePages<TResult, TRequest>(Func<TRequest, INextPageToken?, CancellationToken, Task<ExchangeWebResult<TResult[]>>> paginatedFunc, TRequest request, [EnumeratorCancellation]CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
var result = new List<T>();
|
var result = new List<TResult>();
|
||||||
ExchangeWebResult<T[]> batch;
|
ExchangeWebResult<TResult[]> batch;
|
||||||
INextPageToken? nextPageToken = null;
|
INextPageToken? nextPageToken = null;
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
@@ -383,5 +387,4 @@ namespace CryptoExchange.Net
|
|||||||
// Unknown decimal format, return null
|
// Unknown decimal format, return null
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,16 @@
|
|||||||
using CryptoExchange.Net.SharedApis;
|
using CryptoExchange.Net.SharedApis;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace CryptoExchange.Net
|
namespace CryptoExchange.Net;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Cache for symbol parsing
|
||||||
|
/// </summary>
|
||||||
|
public static class ExchangeSymbolCache
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Cache for symbol parsing
|
|
||||||
/// </summary>
|
|
||||||
public static class ExchangeSymbolCache
|
|
||||||
{
|
|
||||||
private static ConcurrentDictionary<string, ExchangeInfo> _symbolInfos = new ConcurrentDictionary<string, ExchangeInfo>();
|
private static ConcurrentDictionary<string, ExchangeInfo> _symbolInfos = new ConcurrentDictionary<string, ExchangeInfo>();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -66,5 +65,4 @@ namespace CryptoExchange.Net
|
|||||||
Symbols = symbols;
|
Symbols = symbols;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO.Compression;
|
using System.IO.Compression;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
@@ -10,17 +10,14 @@ using CryptoExchange.Net.Objects;
|
|||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using CryptoExchange.Net.SharedApis;
|
using CryptoExchange.Net.SharedApis;
|
||||||
using System.Text.Json.Serialization.Metadata;
|
|
||||||
using System.Text.Json;
|
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace CryptoExchange.Net
|
namespace CryptoExchange.Net;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Helper methods
|
||||||
|
/// </summary>
|
||||||
|
public static class ExtensionMethods
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Helper methods
|
|
||||||
/// </summary>
|
|
||||||
public static class ExtensionMethods
|
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Add a parameter
|
/// Add a parameter
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -416,36 +413,6 @@ namespace CryptoExchange.Net
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static bool IsDelivery(this TradingMode type) => type == TradingMode.DeliveryInverse || type == TradingMode.DeliveryLinear;
|
public static bool IsDelivery(this TradingMode type) => type == TradingMode.DeliveryInverse || type == TradingMode.DeliveryLinear;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Whether the account type is a futures account
|
|
||||||
/// </summary>
|
|
||||||
public static bool IsFuturesAccount(this SharedAccountType type) =>
|
|
||||||
type == SharedAccountType.PerpetualLinearFutures
|
|
||||||
|| type == SharedAccountType.DeliveryLinearFutures
|
|
||||||
|| type == SharedAccountType.PerpetualInverseFutures
|
|
||||||
|| type == SharedAccountType.DeliveryInverseFutures;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Whether the account type is a margin account
|
|
||||||
/// </summary>
|
|
||||||
public static bool IsMarginAccount(this SharedAccountType type) =>
|
|
||||||
type == SharedAccountType.CrossMargin
|
|
||||||
|| type == SharedAccountType.IsolatedMargin;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Map a TradingMode value to a SharedAccountType enum value
|
|
||||||
/// </summary>
|
|
||||||
public static SharedAccountType ToAccountType(this TradingMode mode)
|
|
||||||
{
|
|
||||||
if (mode == TradingMode.Spot) return SharedAccountType.Spot;
|
|
||||||
if (mode == TradingMode.PerpetualLinear) return SharedAccountType.PerpetualLinearFutures;
|
|
||||||
if (mode == TradingMode.PerpetualInverse) return SharedAccountType.PerpetualInverseFutures;
|
|
||||||
if (mode == TradingMode.DeliveryInverse) return SharedAccountType.DeliveryInverseFutures;
|
|
||||||
if (mode == TradingMode.DeliveryLinear) return SharedAccountType.DeliveryLinearFutures;
|
|
||||||
|
|
||||||
throw new ArgumentException(nameof(mode), "Unmapped trading mode");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Register rest client interfaces
|
/// Register rest client interfaces
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -475,8 +442,6 @@ namespace CryptoExchange.Net
|
|||||||
services.AddTransient(x => (IFeeRestClient)client(x)!);
|
services.AddTransient(x => (IFeeRestClient)client(x)!);
|
||||||
if (typeof(IBookTickerRestClient).IsAssignableFrom(typeof(T)))
|
if (typeof(IBookTickerRestClient).IsAssignableFrom(typeof(T)))
|
||||||
services.AddTransient(x => (IBookTickerRestClient)client(x)!);
|
services.AddTransient(x => (IBookTickerRestClient)client(x)!);
|
||||||
if (typeof(ITransferRestClient).IsAssignableFrom(typeof(T)))
|
|
||||||
services.AddTransient(x => (ITransferRestClient)client(x)!);
|
|
||||||
|
|
||||||
if (typeof(ISpotOrderRestClient).IsAssignableFrom(typeof(T)))
|
if (typeof(ISpotOrderRestClient).IsAssignableFrom(typeof(T)))
|
||||||
services.AddTransient(x => (ISpotOrderRestClient)client(x)!);
|
services.AddTransient(x => (ISpotOrderRestClient)client(x)!);
|
||||||
@@ -551,6 +516,5 @@ namespace CryptoExchange.Net
|
|||||||
|
|
||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,15 @@
|
|||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Interfaces
|
namespace CryptoExchange.Net.Interfaces;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Time provider
|
||||||
|
/// </summary>
|
||||||
|
internal interface IAuthTimeProvider
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Time provider
|
|
||||||
/// </summary>
|
|
||||||
internal interface IAuthTimeProvider
|
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get current time
|
/// Get current time
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
DateTime GetTime();
|
DateTime GetTime();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,15 @@
|
|||||||
using CryptoExchange.Net.Authentication;
|
using CryptoExchange.Net.Authentication;
|
||||||
using CryptoExchange.Net.Objects;
|
|
||||||
using CryptoExchange.Net.Objects.Options;
|
using CryptoExchange.Net.Objects.Options;
|
||||||
using CryptoExchange.Net.SharedApis;
|
using CryptoExchange.Net.SharedApis;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Interfaces
|
namespace CryptoExchange.Net.Interfaces;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Base api client
|
||||||
|
/// </summary>
|
||||||
|
public interface IBaseApiClient
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Base api client
|
|
||||||
/// </summary>
|
|
||||||
public interface IBaseApiClient
|
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Base address
|
/// Base address
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -44,5 +43,4 @@ namespace CryptoExchange.Net.Interfaces
|
|||||||
/// <typeparam name="T">Api credentials type</typeparam>
|
/// <typeparam name="T">Api credentials type</typeparam>
|
||||||
/// <param name="options">Options to set</param>
|
/// <param name="options">Options to set</param>
|
||||||
void SetOptions<T>(UpdateOptions<T> options) where T : ApiCredentials;
|
void SetOptions<T>(UpdateOptions<T> options) where T : ApiCredentials;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,17 +1,16 @@
|
|||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Interfaces
|
namespace CryptoExchange.Net.Interfaces;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Client for accessing REST API's for different exchanges
|
||||||
|
/// </summary>
|
||||||
|
public interface ICryptoRestClient
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Client for accessing REST API's for different exchanges
|
|
||||||
/// </summary>
|
|
||||||
public interface ICryptoRestClient
|
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Try get
|
/// Try get
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T"></typeparam>
|
/// <typeparam name="T"></typeparam>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
T TryGet<T>(Func<T> createFunc);
|
T TryGet<T>(Func<T> createFunc);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,17 +1,16 @@
|
|||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Interfaces
|
namespace CryptoExchange.Net.Interfaces;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Client for accessing Websocket API's for different exchanges
|
||||||
|
/// </summary>
|
||||||
|
public interface ICryptoSocketClient
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Client for accessing Websocket API's for different exchanges
|
|
||||||
/// </summary>
|
|
||||||
public interface ICryptoSocketClient
|
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Try get a client by type for the service collection
|
/// Try get a client by type for the service collection
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T"></typeparam>
|
/// <typeparam name="T"></typeparam>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
T TryGet<T>(Func<T> createFunc);
|
T TryGet<T>(Func<T> createFunc);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
namespace CryptoExchange.Net.Interfaces
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Service for an exchange
|
|
||||||
/// </summary>
|
|
||||||
public interface IExchangeService
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The exchange the service is for
|
|
||||||
/// </summary>
|
|
||||||
public string ExchangeName { get; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,18 +1,19 @@
|
|||||||
using CryptoExchange.Net.Converters.MessageParsing;
|
using CryptoExchange.Net.Converters.MessageParsing;
|
||||||
using CryptoExchange.Net.Objects;
|
using CryptoExchange.Net.Objects;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
#if NET5_0_OR_GREATER
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
#endif
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Interfaces
|
namespace CryptoExchange.Net.Interfaces;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Message accessor
|
||||||
|
/// </summary>
|
||||||
|
public interface IMessageAccessor
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Message accessor
|
|
||||||
/// </summary>
|
|
||||||
public interface IMessageAccessor
|
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Is this a valid message
|
/// Is this a valid message
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -81,30 +82,29 @@ namespace CryptoExchange.Net.Interfaces
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
string GetOriginalString();
|
string GetOriginalString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Stream message accessor
|
/// Stream message accessor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IStreamMessageAccessor : IMessageAccessor
|
public interface IStreamMessageAccessor : IMessageAccessor
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Load a stream message
|
/// Load a stream message
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="stream"></param>
|
/// <param name="stream"></param>
|
||||||
/// <param name="bufferStream"></param>
|
/// <param name="bufferStream"></param>
|
||||||
Task<CallResult> Read(Stream stream, bool bufferStream);
|
Task<CallResult> Read(Stream stream, bool bufferStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Byte message accessor
|
/// Byte message accessor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IByteMessageAccessor : IMessageAccessor
|
public interface IByteMessageAccessor : IMessageAccessor
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Load a data message
|
/// Load a data message
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="data"></param>
|
/// <param name="data"></param>
|
||||||
CallResult Read(ReadOnlyMemory<byte> data);
|
CallResult Read(ReadOnlyMemory<byte> data);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,16 @@
|
|||||||
using CryptoExchange.Net.Objects;
|
using CryptoExchange.Net.Objects;
|
||||||
using CryptoExchange.Net.Objects.Sockets;
|
using CryptoExchange.Net.Objects.Sockets;
|
||||||
using CryptoExchange.Net.Sockets;
|
using CryptoExchange.Net.Sockets;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Interfaces
|
namespace CryptoExchange.Net.Interfaces;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Message processor
|
||||||
|
/// </summary>
|
||||||
|
public interface IMessageProcessor
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Message processor
|
|
||||||
/// </summary>
|
|
||||||
public interface IMessageProcessor
|
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Id of the processor
|
/// Id of the processor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -31,5 +30,4 @@ namespace CryptoExchange.Net.Interfaces
|
|||||||
/// <param name="type"></param>
|
/// <param name="type"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
CallResult<object> Deserialize(IMessageAccessor accessor, Type type);
|
CallResult<object> Deserialize(IMessageAccessor accessor, Type type);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,37 +1,34 @@
|
|||||||
using System.Diagnostics.CodeAnalysis;
|
namespace CryptoExchange.Net.Interfaces;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Interfaces
|
/// <summary>
|
||||||
|
/// Serializer interface
|
||||||
|
/// </summary>
|
||||||
|
public interface IMessageSerializer
|
||||||
{
|
{
|
||||||
/// <summary>
|
}
|
||||||
/// Serializer interface
|
|
||||||
/// </summary>
|
|
||||||
public interface IMessageSerializer
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Serialize to byte array
|
/// Serialize to byte array
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IByteMessageSerializer: IMessageSerializer
|
public interface IByteMessageSerializer: IMessageSerializer
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Serialize an object to a string
|
/// Serialize an object to a string
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="message"></param>
|
/// <param name="message"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
byte[] Serialize<T>(T message);
|
byte[] Serialize<T>(T message);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Serialize to string
|
/// Serialize to string
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IStringMessageSerializer: IMessageSerializer
|
public interface IStringMessageSerializer: IMessageSerializer
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Serialize an object to a string
|
/// Serialize an object to a string
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="message"></param>
|
/// <param name="message"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
string Serialize<T>(T message);
|
string Serialize<T>(T message);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
namespace CryptoExchange.Net.Interfaces
|
namespace CryptoExchange.Net.Interfaces;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A provider for a nonce value used when signing requests
|
||||||
|
/// </summary>
|
||||||
|
public interface INonceProvider
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// A provider for a nonce value used when signing requests
|
|
||||||
/// </summary>
|
|
||||||
public interface INonceProvider
|
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get nonce value. Nonce value should be unique and incremental for each call
|
/// Get nonce value. Nonce value should be unique and incremental for each call
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>Nonce value</returns>
|
/// <returns>Nonce value</returns>
|
||||||
long GetNonce();
|
long GetNonce();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
using CryptoExchange.Net.Objects.Options;
|
using CryptoExchange.Net.Objects.Options;
|
||||||
using CryptoExchange.Net.SharedApis;
|
using CryptoExchange.Net.SharedApis;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Interfaces
|
namespace CryptoExchange.Net.Interfaces;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Factory for ISymbolOrderBook instances
|
||||||
|
/// </summary>
|
||||||
|
public interface IOrderBookFactory<TOptions> where TOptions : OrderBookOptions
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Factory for ISymbolOrderBook instances
|
|
||||||
/// </summary>
|
|
||||||
public interface IOrderBookFactory<TOptions> where TOptions : OrderBookOptions
|
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a new order book by symbol name
|
/// Create a new order book by symbol name
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -31,5 +31,4 @@ namespace CryptoExchange.Net.Interfaces
|
|||||||
/// <param name="options">Options for the order book</param>
|
/// <param name="options">Options for the order book</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public ISymbolOrderBook Create(SharedSymbol symbol, Action<TOptions>? options = null);
|
public ISymbolOrderBook Create(SharedSymbol symbol, Action<TOptions>? options = null);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,13 +4,13 @@ using System.Net.Http;
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Interfaces
|
namespace CryptoExchange.Net.Interfaces;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Rate limiter interface
|
||||||
|
/// </summary>
|
||||||
|
public interface IRateLimiter
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Rate limiter interface
|
|
||||||
/// </summary>
|
|
||||||
public interface IRateLimiter
|
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Limit a request based on previous requests made
|
/// Limit a request based on previous requests made
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -24,5 +24,4 @@ namespace CryptoExchange.Net.Interfaces
|
|||||||
/// <param name="ct">Cancellation token to cancel waiting</param>
|
/// <param name="ct">Cancellation token to cancel waiting</param>
|
||||||
/// <returns>The time in milliseconds spend waiting</returns>
|
/// <returns>The time in milliseconds spend waiting</returns>
|
||||||
Task<CallResult<int>> LimitRequestAsync(ILogger log, string endpoint, HttpMethod method, bool signed, string? apiKey, RateLimitingBehaviour limitBehaviour, int requestWeight, CancellationToken ct);
|
Task<CallResult<int>> LimitRequestAsync(ILogger log, string endpoint, HttpMethod method, bool signed, string? apiKey, RateLimitingBehaviour limitBehaviour, int requestWeight, CancellationToken ct);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Interfaces
|
namespace CryptoExchange.Net.Interfaces;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Request interface
|
||||||
|
/// </summary>
|
||||||
|
public interface IRequest
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Request interface
|
|
||||||
/// </summary>
|
|
||||||
public interface IRequest
|
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Accept header
|
/// Accept header
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -28,10 +28,6 @@ namespace CryptoExchange.Net.Interfaces
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
Uri Uri { get; }
|
Uri Uri { get; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// HTTP protocol version
|
|
||||||
/// </summary>
|
|
||||||
Version HttpVersion { get; }
|
|
||||||
/// <summary>
|
|
||||||
/// internal request id for tracing
|
/// internal request id for tracing
|
||||||
/// </summary>
|
/// </summary>
|
||||||
int RequestId { get; }
|
int RequestId { get; }
|
||||||
@@ -66,5 +62,4 @@ namespace CryptoExchange.Net.Interfaces
|
|||||||
/// <param name="cancellationToken"></param>
|
/// <param name="cancellationToken"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<IResponse> GetResponseAsync(CancellationToken cancellationToken);
|
Task<IResponse> GetResponseAsync(CancellationToken cancellationToken);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,33 +1,35 @@
|
|||||||
using CryptoExchange.Net.Objects;
|
using CryptoExchange.Net.Objects;
|
||||||
using CryptoExchange.Net.Objects.Options;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Interfaces
|
namespace CryptoExchange.Net.Interfaces;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Request factory interface
|
||||||
|
/// </summary>
|
||||||
|
public interface IRequestFactory
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Request factory interface
|
|
||||||
/// </summary>
|
|
||||||
public interface IRequestFactory
|
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a request for an uri
|
/// Create a request for an uri
|
||||||
/// </summary>
|
/// </summary>
|
||||||
IRequest Create(Version httpRequestVersion, HttpMethod method, Uri uri, int requestId);
|
/// <param name="method"></param>
|
||||||
|
/// <param name="uri"></param>
|
||||||
|
/// <param name="requestId"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
IRequest Create(HttpMethod method, Uri uri, int requestId);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Configure the requests created by this factory
|
/// Configure the requests created by this factory
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="options">Rest client options</param>
|
/// <param name="requestTimeout">Request timeout to use</param>
|
||||||
/// <param name="httpClient">Optional shared http client instance</param>
|
/// <param name="httpClient">Optional shared http client instance</param>
|
||||||
void Configure(RestExchangeOptions options, HttpClient? httpClient = null);
|
/// <param name="proxy">Optional proxy to use when no http client is provided</param>
|
||||||
|
void Configure(ApiProxy? proxy, TimeSpan requestTimeout, HttpClient? httpClient = null);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Update settings
|
/// Update settings
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="proxy">Proxy to use</param>
|
/// <param name="proxy">Proxy to use</param>
|
||||||
/// <param name="requestTimeout">Request timeout to use</param>
|
/// <param name="requestTimeout">Request timeout to use</param>
|
||||||
/// <param name="httpKeepAliveInterval">Http client keep alive interval</param>
|
void UpdateSettings(ApiProxy? proxy, TimeSpan requestTimeout);
|
||||||
void UpdateSettings(ApiProxy? proxy, TimeSpan requestTimeout, TimeSpan? httpKeepAliveInterval);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,26 +1,20 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Interfaces
|
namespace CryptoExchange.Net.Interfaces;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Response object interface
|
||||||
|
/// </summary>
|
||||||
|
public interface IResponse
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Response object interface
|
|
||||||
/// </summary>
|
|
||||||
public interface IResponse
|
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The response status code
|
/// The response status code
|
||||||
/// </summary>
|
/// </summary>
|
||||||
HttpStatusCode StatusCode { get; }
|
HttpStatusCode StatusCode { get; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Http protocol version
|
|
||||||
/// </summary>
|
|
||||||
Version HttpVersion { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether the status code indicates a success status
|
/// Whether the status code indicates a success status
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -46,5 +40,4 @@ namespace CryptoExchange.Net.Interfaces
|
|||||||
/// Close the response
|
/// Close the response
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void Close();
|
void Close();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
namespace CryptoExchange.Net.Interfaces
|
namespace CryptoExchange.Net.Interfaces;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Base rest API client
|
||||||
|
/// </summary>
|
||||||
|
public interface IRestApiClient : IBaseApiClient
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Base rest API client
|
|
||||||
/// </summary>
|
|
||||||
public interface IRestApiClient : IBaseApiClient
|
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The factory for creating requests. Used for unit testing
|
/// The factory for creating requests. Used for unit testing
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -14,5 +14,4 @@
|
|||||||
/// Total amount of requests made with this API client
|
/// Total amount of requests made with this API client
|
||||||
/// </summary>
|
/// </summary>
|
||||||
int TotalRequestsMade { get; set; }
|
int TotalRequestsMade { get; set; }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
using System;
|
using System;
|
||||||
using CryptoExchange.Net.Objects.Options;
|
using CryptoExchange.Net.Objects.Options;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Interfaces
|
namespace CryptoExchange.Net.Interfaces;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Base class for rest API implementations
|
||||||
|
/// </summary>
|
||||||
|
public interface IRestClient: IDisposable
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Base class for rest API implementations
|
|
||||||
/// </summary>
|
|
||||||
public interface IRestClient: IDisposable
|
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The options provided for this client
|
/// The options provided for this client
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -22,5 +22,4 @@ namespace CryptoExchange.Net.Interfaces
|
|||||||
/// The exchange name
|
/// The exchange name
|
||||||
/// </summary>
|
/// </summary>
|
||||||
string Exchange { get; }
|
string Exchange { get; }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,15 +1,15 @@
|
|||||||
using CryptoExchange.Net.Objects;
|
using CryptoExchange.Net.Objects;
|
||||||
using CryptoExchange.Net.Objects.Options;
|
using CryptoExchange.Net.Objects.Options;
|
||||||
using CryptoExchange.Net.Objects.Sockets;
|
using CryptoExchange.Net.Objects.Sockets;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Interfaces
|
namespace CryptoExchange.Net.Interfaces;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Socket API client
|
||||||
|
/// </summary>
|
||||||
|
public interface ISocketApiClient: IBaseApiClient
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Socket API client
|
|
||||||
/// </summary>
|
|
||||||
public interface ISocketApiClient: IBaseApiClient
|
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The current amount of socket connections on the API client
|
/// The current amount of socket connections on the API client
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -66,5 +66,4 @@ namespace CryptoExchange.Net.Interfaces
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<CallResult> PrepareConnectionsAsync();
|
Task<CallResult> PrepareConnectionsAsync();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,15 +1,15 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using CryptoExchange.Net.Objects.Options;
|
using CryptoExchange.Net.Objects.Options;
|
||||||
using CryptoExchange.Net.Objects.Sockets;
|
using CryptoExchange.Net.Objects.Sockets;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Interfaces
|
namespace CryptoExchange.Net.Interfaces;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Base class for socket API implementations
|
||||||
|
/// </summary>
|
||||||
|
public interface ISocketClient: IDisposable
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Base class for socket API implementations
|
|
||||||
/// </summary>
|
|
||||||
public interface ISocketClient: IDisposable
|
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The exchange name
|
/// The exchange name
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -54,5 +54,4 @@ namespace CryptoExchange.Net.Interfaces
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task UnsubscribeAllAsync();
|
Task UnsubscribeAllAsync();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,16 +1,15 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using CryptoExchange.Net.Objects;
|
using CryptoExchange.Net.Objects;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Interfaces
|
namespace CryptoExchange.Net.Interfaces;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Interface for order book
|
||||||
|
/// </summary>
|
||||||
|
public interface ISymbolOrderBook
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Interface for order book
|
|
||||||
/// </summary>
|
|
||||||
public interface ISymbolOrderBook
|
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The exchange the book is for
|
/// The exchange the book is for
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -127,5 +126,4 @@ namespace CryptoExchange.Net.Interfaces
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
string ToString(int rows);
|
string ToString(int rows);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
namespace CryptoExchange.Net.Interfaces
|
namespace CryptoExchange.Net.Interfaces;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Interface for order book entries
|
||||||
|
/// </summary>
|
||||||
|
public interface ISymbolOrderBookEntry
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Interface for order book entries
|
|
||||||
/// </summary>
|
|
||||||
public interface ISymbolOrderBookEntry
|
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The quantity of the entry
|
/// The quantity of the entry
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -13,16 +13,15 @@
|
|||||||
/// The price of the entry
|
/// The price of the entry
|
||||||
/// </summary>
|
/// </summary>
|
||||||
decimal Price { get; set; }
|
decimal Price { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Interface for order book entries
|
/// Interface for order book entries
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface ISymbolOrderSequencedBookEntry: ISymbolOrderBookEntry
|
public interface ISymbolOrderSequencedBookEntry: ISymbolOrderBookEntry
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sequence of the update
|
/// Sequence of the update
|
||||||
/// </summary>
|
/// </summary>
|
||||||
long Sequence { get; set; }
|
long Sequence { get; set; }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,45 +0,0 @@
|
|||||||
using CryptoExchange.Net.SharedApis;
|
|
||||||
using CryptoExchange.Net.Trackers.Klines;
|
|
||||||
using CryptoExchange.Net.Trackers.Trades;
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Interfaces
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Tracker factory
|
|
||||||
/// </summary>
|
|
||||||
public interface ITrackerFactory
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Whether the factory supports creating a KlineTracker instance for this symbol and interval
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="symbol">The symbol</param>
|
|
||||||
/// <param name="interval">The kline interval</param>
|
|
||||||
bool CanCreateKlineTracker(SharedSymbol symbol, SharedKlineInterval interval);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Create a new kline tracker
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="symbol">The symbol</param>
|
|
||||||
/// <param name="interval">Kline interval</param>
|
|
||||||
/// <param name="limit">The max amount of klines to retain</param>
|
|
||||||
/// <param name="period">The max period the data should be retained</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
IKlineTracker CreateKlineTracker(SharedSymbol symbol, SharedKlineInterval interval, int? limit = null, TimeSpan? period = null);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Whether the factory supports creating a TradeTracker instance for this symbol
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="symbol">The symbol</param>
|
|
||||||
bool CanCreateTradeTracker(SharedSymbol symbol);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Create a new trade tracker for a symbol
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="symbol">The symbol</param>
|
|
||||||
/// <param name="limit">The max amount of trades to retain</param>
|
|
||||||
/// <param name="period">The max period the data should be retained</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
ITradeTracker CreateTradeTracker(SharedSymbol symbol, int? limit = null, TimeSpan? period = null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,16 +1,16 @@
|
|||||||
using CryptoExchange.Net.Objects;
|
using CryptoExchange.Net.Objects;
|
||||||
using System;
|
using System;
|
||||||
using System.Net.WebSockets;
|
using System.Net.WebSockets;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Interfaces
|
namespace CryptoExchange.Net.Interfaces;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Websocket connection interface
|
||||||
|
/// </summary>
|
||||||
|
public interface IWebsocket: IDisposable
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Websocket connection interface
|
|
||||||
/// </summary>
|
|
||||||
public interface IWebsocket: IDisposable
|
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Websocket closed event
|
/// Websocket closed event
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -106,5 +106,4 @@ namespace CryptoExchange.Net.Interfaces
|
|||||||
/// Update proxy setting
|
/// Update proxy setting
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void UpdateProxy(ApiProxy? proxy);
|
void UpdateProxy(ApiProxy? proxy);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
using CryptoExchange.Net.Objects.Sockets;
|
using CryptoExchange.Net.Objects.Sockets;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Interfaces
|
namespace CryptoExchange.Net.Interfaces;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Websocket factory interface
|
||||||
|
/// </summary>
|
||||||
|
public interface IWebsocketFactory
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Websocket factory interface
|
|
||||||
/// </summary>
|
|
||||||
public interface IWebsocketFactory
|
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a websocket for an url
|
/// Create a websocket for an url
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -15,5 +15,4 @@ namespace CryptoExchange.Net.Interfaces
|
|||||||
/// <param name="parameters">The parameters to use for the connection</param>
|
/// <param name="parameters">The parameters to use for the connection</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
IWebsocket CreateWebsocket(ILogger logger, WebSocketParameters parameters);
|
IWebsocket CreateWebsocket(ILogger logger, WebSocketParameters parameters);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,62 +1,15 @@
|
|||||||
using CryptoExchange.Net.Objects;
|
namespace CryptoExchange.Net;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Net;
|
|
||||||
using System.Net.Http;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace CryptoExchange.Net
|
/// <summary>
|
||||||
|
/// Helpers for client libraries
|
||||||
|
/// </summary>
|
||||||
|
public static class LibraryHelpers
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Helpers for client libraries
|
|
||||||
/// </summary>
|
|
||||||
public static class LibraryHelpers
|
|
||||||
{
|
|
||||||
private static ILogger? _staticLogger;
|
|
||||||
/// <summary>
|
|
||||||
/// Static logger
|
|
||||||
/// </summary>
|
|
||||||
public static ILogger? StaticLogger
|
|
||||||
{
|
|
||||||
get => _staticLogger;
|
|
||||||
internal set
|
|
||||||
{
|
|
||||||
if (_staticLogger != null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_staticLogger = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Client order id separator
|
/// Client order id separator
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const string ClientOrderIdSeparator = "JK";
|
public const string ClientOrderIdSeparator = "JK";
|
||||||
|
|
||||||
private static Dictionary<string, string> _defaultClientReferences = new Dictionary<string, string>()
|
|
||||||
{
|
|
||||||
{ "Binance.Spot", "x-VICEW9VV" },
|
|
||||||
{ "Binance.Futures", "x-d63tKbx3" },
|
|
||||||
{ "BingX", "easytrading" },
|
|
||||||
{ "Bitfinex", "kCCe-CNBO" },
|
|
||||||
{ "Bitget", "6x21p" },
|
|
||||||
{ "BitMart", "EASYTRADING0001" },
|
|
||||||
{ "BitMEX", "Sent from JKorf" },
|
|
||||||
{ "BloFin", "5c07cf695885c282" },
|
|
||||||
{ "Bybit", "Zx000356" },
|
|
||||||
{ "CoinEx", "x-147866029-" },
|
|
||||||
{ "GateIo", "copytraderpw" },
|
|
||||||
{ "HTX", "AA1ef14811" },
|
|
||||||
{ "Kucoin.FuturesName", "Easytradingfutures" },
|
|
||||||
{ "Kucoin.FuturesKey", "9e08c05f-454d-4580-82af-2f4c7027fd00" },
|
|
||||||
{ "Kucoin.SpotName", "Easytrading" },
|
|
||||||
{ "Kucoin.SpotKey", "f8ae62cb-2b3d-420c-8c98-e1c17dd4e30a" },
|
|
||||||
{ "Mexc", "EASYT" },
|
|
||||||
{ "OKX", "1425d83a94fbBCDE" },
|
|
||||||
{ "XT", "4XWeqN10M1fcoI5L" },
|
|
||||||
};
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Apply broker id to a client order id
|
/// Apply broker id to a client order id
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -86,74 +39,4 @@ namespace CryptoExchange.Net
|
|||||||
|
|
||||||
return clientOrderId;
|
return clientOrderId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get the client reference for an exchange if available
|
|
||||||
/// </summary>
|
|
||||||
public static string GetClientReference(Func<string?> optionsReference, string exchange, string? topic = null)
|
|
||||||
{
|
|
||||||
var optionsValue = optionsReference();
|
|
||||||
if (!string.IsNullOrEmpty(optionsValue))
|
|
||||||
return optionsValue!;
|
|
||||||
|
|
||||||
var key = exchange;
|
|
||||||
if (topic != null)
|
|
||||||
key += "." + topic;
|
|
||||||
|
|
||||||
return _defaultClientReferences.TryGetValue(key, out var id) ? id : throw new KeyNotFoundException($"{exchange} not found in configuration");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Create a new HttpMessageHandler instance
|
|
||||||
/// </summary>
|
|
||||||
public static HttpMessageHandler CreateHttpClientMessageHandler(ApiProxy? proxy, TimeSpan? keepAliveInterval)
|
|
||||||
{
|
|
||||||
#if NET5_0_OR_GREATER
|
|
||||||
var socketHandler = new SocketsHttpHandler();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (keepAliveInterval != null && keepAliveInterval != TimeSpan.Zero)
|
|
||||||
{
|
|
||||||
socketHandler.KeepAlivePingPolicy = HttpKeepAlivePingPolicy.Always;
|
|
||||||
socketHandler.KeepAlivePingDelay = keepAliveInterval.Value;
|
|
||||||
socketHandler.KeepAlivePingTimeout = TimeSpan.FromSeconds(10);
|
|
||||||
}
|
|
||||||
|
|
||||||
socketHandler.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
|
|
||||||
socketHandler.DefaultProxyCredentials = CredentialCache.DefaultCredentials;
|
|
||||||
}
|
|
||||||
catch (PlatformNotSupportedException) { }
|
|
||||||
catch (NotImplementedException) { } // Mono runtime throws NotImplementedException
|
|
||||||
|
|
||||||
if (proxy != null)
|
|
||||||
{
|
|
||||||
socketHandler.Proxy = new WebProxy
|
|
||||||
{
|
|
||||||
Address = new Uri($"{proxy.Host}:{proxy.Port}"),
|
|
||||||
Credentials = proxy.Password == null ? null : new NetworkCredential(proxy.Login, proxy.Password)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return socketHandler;
|
|
||||||
#else
|
|
||||||
var httpHandler = new HttpClientHandler();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
httpHandler.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
|
|
||||||
httpHandler.DefaultProxyCredentials = CredentialCache.DefaultCredentials;
|
|
||||||
}
|
|
||||||
catch (PlatformNotSupportedException) { }
|
|
||||||
catch (NotImplementedException) { } // Mono runtime throws NotImplementedException
|
|
||||||
|
|
||||||
if (proxy != null)
|
|
||||||
{
|
|
||||||
httpHandler.Proxy = new WebProxy
|
|
||||||
{
|
|
||||||
Address = new Uri($"{proxy.Host}:{proxy.Port}"),
|
|
||||||
Credentials = proxy.Password == null ? null : new NetworkCredential(proxy.Login, proxy.Password)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return httpHandler;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-6
@@ -1,11 +1,11 @@
|
|||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Logging.Extensions
|
namespace CryptoExchange.Net.Logging.Extensions;
|
||||||
{
|
|
||||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||||
public static class CryptoExchangeWebSocketClientLoggingExtension
|
public static class CryptoExchangeWebSocketClientLoggingExtension
|
||||||
{
|
{
|
||||||
private static readonly Action<ILogger, int, Exception?> _connecting;
|
private static readonly Action<ILogger, int, Exception?> _connecting;
|
||||||
private static readonly Action<ILogger, int, string, Exception?> _connectionFailed;
|
private static readonly Action<ILogger, int, string, Exception?> _connectionFailed;
|
||||||
private static readonly Action<ILogger, int, Exception?> _connectingCanceled;
|
private static readonly Action<ILogger, int, Exception?> _connectingCanceled;
|
||||||
@@ -383,5 +383,4 @@ namespace CryptoExchange.Net.Logging.Extensions
|
|||||||
{
|
{
|
||||||
_connectingCanceled(logger, socketId, null);
|
_connectingCanceled(logger, socketId, null);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Logging.Extensions
|
namespace CryptoExchange.Net.Logging.Extensions;
|
||||||
{
|
|
||||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||||
public static class RateLimitGateLoggingExtensions
|
public static class RateLimitGateLoggingExtensions
|
||||||
{
|
{
|
||||||
private static readonly Action<ILogger, int, string, string, string, Exception?> _rateLimitRequestFailed;
|
private static readonly Action<ILogger, int, string, string, string, Exception?> _rateLimitRequestFailed;
|
||||||
private static readonly Action<ILogger, int, string, string, Exception?> _rateLimitConnectionFailed;
|
private static readonly Action<ILogger, int, string, string, Exception?> _rateLimitConnectionFailed;
|
||||||
private static readonly Action<ILogger, int, string, TimeSpan, string, string, Exception?> _rateLimitDelayingRequest;
|
private static readonly Action<ILogger, int, string, TimeSpan, string, string, Exception?> _rateLimitDelayingRequest;
|
||||||
@@ -75,5 +75,4 @@ namespace CryptoExchange.Net.Logging.Extensions
|
|||||||
{
|
{
|
||||||
_rateLimitAppliedRequest(logger, requestIdId, path, guard, limit, current, null);
|
_rateLimitAppliedRequest(logger, requestIdId, path, guard, limit, current, null);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
using CryptoExchange.Net.Objects;
|
using CryptoExchange.Net.Objects;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using System;
|
using System;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Logging.Extensions
|
namespace CryptoExchange.Net.Logging.Extensions;
|
||||||
{
|
|
||||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||||
public static class RestApiClientLoggingExtensions
|
public static class RestApiClientLoggingExtensions
|
||||||
{
|
{
|
||||||
private static readonly Action<ILogger, int?, int?, long, string?, string?, Exception?> _restApiErrorReceived;
|
private static readonly Action<ILogger, int?, int?, long, string?, string?, Exception?> _restApiErrorReceived;
|
||||||
private static readonly Action<ILogger, int?, int?, long, string?, Exception?> _restApiResponseReceived;
|
private static readonly Action<ILogger, int?, int?, long, string?, Exception?> _restApiResponseReceived;
|
||||||
private static readonly Action<ILogger, int, string, Exception?> _restApiFailedToSyncTime;
|
private static readonly Action<ILogger, int, string, Exception?> _restApiFailedToSyncTime;
|
||||||
@@ -155,5 +155,4 @@ namespace CryptoExchange.Net.Logging.Extensions
|
|||||||
{
|
{
|
||||||
_restApiCancellationRequested(logger, requestId, null);
|
_restApiCancellationRequested(logger, requestId, null);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Logging.Extensions
|
namespace CryptoExchange.Net.Logging.Extensions;
|
||||||
{
|
|
||||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||||
public static class SocketApiClientLoggingExtension
|
public static class SocketApiClientLoggingExtension
|
||||||
{
|
{
|
||||||
private static readonly Action<ILogger, int, Exception?> _failedToAddSubscriptionRetryOnDifferentConnection;
|
private static readonly Action<ILogger, int, Exception?> _failedToAddSubscriptionRetryOnDifferentConnection;
|
||||||
private static readonly Action<ILogger, int, Exception?> _hasBeenPausedCantSubscribeAtThisMoment;
|
private static readonly Action<ILogger, int, Exception?> _hasBeenPausedCantSubscribeAtThisMoment;
|
||||||
private static readonly Action<ILogger, int, string?, Exception?> _failedToSubscribe;
|
private static readonly Action<ILogger, int, string?, Exception?> _failedToSubscribe;
|
||||||
@@ -23,8 +23,6 @@ namespace CryptoExchange.Net.Logging.Extensions
|
|||||||
private static readonly Action<ILogger, int, int, Exception?> _unsubscribingSubscription;
|
private static readonly Action<ILogger, int, int, Exception?> _unsubscribingSubscription;
|
||||||
private static readonly Action<ILogger, int, Exception?> _reconnectingAllConnections;
|
private static readonly Action<ILogger, int, Exception?> _reconnectingAllConnections;
|
||||||
private static readonly Action<ILogger, DateTime, Exception?> _addingRetryAfterGuard;
|
private static readonly Action<ILogger, DateTime, Exception?> _addingRetryAfterGuard;
|
||||||
private static readonly Action<ILogger, Exception?> _timeoutWaitingForReconnectingSocket;
|
|
||||||
private static readonly Action<ILogger, long, Exception?> _waitedForReconnectingSocket;
|
|
||||||
|
|
||||||
static SocketApiClientLoggingExtension()
|
static SocketApiClientLoggingExtension()
|
||||||
{
|
{
|
||||||
@@ -112,16 +110,6 @@ namespace CryptoExchange.Net.Logging.Extensions
|
|||||||
LogLevel.Warning,
|
LogLevel.Warning,
|
||||||
new EventId(3018, "AddRetryAfterGuard"),
|
new EventId(3018, "AddRetryAfterGuard"),
|
||||||
"Adding RetryAfterGuard ({RetryAfter}) because the connection attempt was rate limited");
|
"Adding RetryAfterGuard ({RetryAfter}) because the connection attempt was rate limited");
|
||||||
|
|
||||||
_timeoutWaitingForReconnectingSocket = LoggerMessage.Define(
|
|
||||||
LogLevel.Debug,
|
|
||||||
new EventId(3019, "TimeoutWaitingForReconnectingSocket"),
|
|
||||||
"Timeout while waiting for existing socket reconnection, failing request");
|
|
||||||
|
|
||||||
_waitedForReconnectingSocket = LoggerMessage.Define<long>(
|
|
||||||
LogLevel.Trace,
|
|
||||||
new EventId(3020, "WaitedForReconnectingSocket"),
|
|
||||||
"Waited for reconnecting socket for {Timespan}ms");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void FailedToAddSubscriptionRetryOnDifferentConnection(this ILogger logger, int socketId)
|
public static void FailedToAddSubscriptionRetryOnDifferentConnection(this ILogger logger, int socketId)
|
||||||
@@ -208,14 +196,4 @@ namespace CryptoExchange.Net.Logging.Extensions
|
|||||||
{
|
{
|
||||||
_addingRetryAfterGuard(logger, retryAfter, null);
|
_addingRetryAfterGuard(logger, retryAfter, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void TimeoutWaitingForReconnectingSocket(this ILogger logger)
|
|
||||||
{
|
|
||||||
_timeoutWaitingForReconnectingSocket(logger, null);
|
|
||||||
}
|
|
||||||
public static void WaitedForReconnectingSocket(this ILogger logger, long milliseconds)
|
|
||||||
{
|
|
||||||
_waitedForReconnectingSocket(logger, milliseconds, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,19 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Net.WebSockets;
|
using System.Net.WebSockets;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Logging.Extensions
|
namespace CryptoExchange.Net.Logging.Extensions;
|
||||||
{
|
|
||||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||||
public static class SocketConnectionLoggingExtension
|
public static class SocketConnectionLoggingExtension
|
||||||
{
|
{
|
||||||
private static readonly Action<ILogger, int, bool, Exception?> _activityPaused;
|
private static readonly Action<ILogger, int, bool, Exception?> _activityPaused;
|
||||||
private static readonly Action<ILogger, int, Sockets.SocketConnection.SocketStatus, Sockets.SocketConnection.SocketStatus, Exception?> _socketStatusChanged;
|
private static readonly Action<ILogger, int, Sockets.SocketConnection.SocketStatus, Sockets.SocketConnection.SocketStatus, Exception?> _socketStatusChanged;
|
||||||
private static readonly Action<ILogger, int, string?, Exception?> _failedReconnectProcessing;
|
private static readonly Action<ILogger, int, string?, Exception?> _failedReconnectProcessing;
|
||||||
private static readonly Action<ILogger, int, Exception?> _unknownExceptionWhileProcessingReconnection;
|
private static readonly Action<ILogger, int, Exception?> _unknownExceptionWhileProcessingReconnection;
|
||||||
private static readonly Action<ILogger, int, WebSocketError, string?, Exception?> _webSocketErrorCodeAndDetails;
|
private static readonly Action<ILogger, int, WebSocketError, string?, Exception?> _webSocketErrorCodeAndDetails;
|
||||||
private static readonly Action<ILogger, int, string?, Exception?> _webSocketError;
|
private static readonly Action<ILogger, int, string?, Exception?> _webSocketError;
|
||||||
|
private static readonly Action<ILogger, int, int, Exception?> _messageSentNotPending;
|
||||||
private static readonly Action<ILogger, int, string, Exception?> _receivedData;
|
private static readonly Action<ILogger, int, string, Exception?> _receivedData;
|
||||||
private static readonly Action<ILogger, int, string, Exception?> _failedToParse;
|
private static readonly Action<ILogger, int, string, Exception?> _failedToParse;
|
||||||
private static readonly Action<ILogger, int, string, Exception?> _failedToEvaluateMessage;
|
private static readonly Action<ILogger, int, string, Exception?> _failedToEvaluateMessage;
|
||||||
@@ -71,6 +72,11 @@ namespace CryptoExchange.Net.Logging.Extensions
|
|||||||
new EventId(2005, "WebSocketError"),
|
new EventId(2005, "WebSocketError"),
|
||||||
"[Sckt {SocketId}] error: {ErrorMessage}");
|
"[Sckt {SocketId}] error: {ErrorMessage}");
|
||||||
|
|
||||||
|
_messageSentNotPending = LoggerMessage.Define<int, int>(
|
||||||
|
LogLevel.Debug,
|
||||||
|
new EventId(2006, "MessageSentNotPending"),
|
||||||
|
"[Sckt {SocketId}] [Req {RequestId}] message sent, but not pending");
|
||||||
|
|
||||||
_receivedData = LoggerMessage.Define<int, string>(
|
_receivedData = LoggerMessage.Define<int, string>(
|
||||||
LogLevel.Trace,
|
LogLevel.Trace,
|
||||||
new EventId(2007, "ReceivedData"),
|
new EventId(2007, "ReceivedData"),
|
||||||
@@ -228,6 +234,11 @@ namespace CryptoExchange.Net.Logging.Extensions
|
|||||||
_webSocketError(logger, socketId, errorMessage, e);
|
_webSocketError(logger, socketId, errorMessage, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void MessageSentNotPending(this ILogger logger, int socketId, int requestId)
|
||||||
|
{
|
||||||
|
_messageSentNotPending(logger, socketId, requestId, null);
|
||||||
|
}
|
||||||
|
|
||||||
public static void ReceivedData(this ILogger logger, int socketId, string originalData)
|
public static void ReceivedData(this ILogger logger, int socketId, string originalData)
|
||||||
{
|
{
|
||||||
_receivedData(logger, socketId, originalData, null);
|
_receivedData(logger, socketId, originalData, null);
|
||||||
@@ -334,5 +345,4 @@ namespace CryptoExchange.Net.Logging.Extensions
|
|||||||
{
|
{
|
||||||
_sendingByteData(logger, socketId, requestId, length, null);
|
_sendingByteData(logger, socketId, requestId, length, null);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
using System;
|
using System;
|
||||||
using CryptoExchange.Net.Objects;
|
using CryptoExchange.Net.Objects;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Logging.Extensions
|
namespace CryptoExchange.Net.Logging.Extensions;
|
||||||
{
|
|
||||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||||
|
|
||||||
public static class SymbolOrderBookLoggingExtensions
|
public static class SymbolOrderBookLoggingExtensions
|
||||||
{
|
{
|
||||||
private static readonly Action<ILogger, string, string, OrderBookStatus, OrderBookStatus, Exception?> _orderBookStatusChanged;
|
private static readonly Action<ILogger, string, string, OrderBookStatus, OrderBookStatus, Exception?> _orderBookStatusChanged;
|
||||||
private static readonly Action<ILogger, string, string, Exception?> _orderBookStarting;
|
private static readonly Action<ILogger, string, string, Exception?> _orderBookStarting;
|
||||||
private static readonly Action<ILogger, string, string, Exception?> _orderBookStoppedStarting;
|
private static readonly Action<ILogger, string, string, Exception?> _orderBookStoppedStarting;
|
||||||
@@ -233,5 +233,4 @@ namespace CryptoExchange.Net.Logging.Extensions
|
|||||||
{
|
{
|
||||||
_orderBookOutOfSyncChecksum(logger, api, symbol, null);
|
_orderBookOutOfSyncChecksum(logger, api, symbol, null);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
using System;
|
using System;
|
||||||
using CryptoExchange.Net.Objects;
|
using CryptoExchange.Net.Objects;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Logging.Extensions
|
namespace CryptoExchange.Net.Logging.Extensions;
|
||||||
{
|
|
||||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||||
|
|
||||||
public static class TrackerLoggingExtensions
|
public static class TrackerLoggingExtensions
|
||||||
{
|
{
|
||||||
private static readonly Action<ILogger, string, SyncStatus, SyncStatus, Exception?> _klineTrackerStatusChanged;
|
private static readonly Action<ILogger, string, SyncStatus, SyncStatus, Exception?> _klineTrackerStatusChanged;
|
||||||
private static readonly Action<ILogger, string, Exception?> _klineTrackerStarting;
|
private static readonly Action<ILogger, string, Exception?> _klineTrackerStarting;
|
||||||
private static readonly Action<ILogger, string, string, Exception?> _klineTrackerStartFailed;
|
private static readonly Action<ILogger, string, string, Exception?> _klineTrackerStartFailed;
|
||||||
@@ -287,5 +287,4 @@ namespace CryptoExchange.Net.Logging.Extensions
|
|||||||
{
|
{
|
||||||
_tradeTrackerConnectionRestored(logger, symbol, null);
|
_tradeTrackerConnectionRestored(logger, symbol, null);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
namespace CryptoExchange.Net.Objects
|
namespace CryptoExchange.Net.Objects;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Proxy info
|
||||||
|
/// </summary>
|
||||||
|
public class ApiProxy
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Proxy info
|
|
||||||
/// </summary>
|
|
||||||
public class ApiProxy
|
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The host address of the proxy
|
/// The host address of the proxy
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -38,5 +38,4 @@
|
|||||||
Login = login;
|
Login = login;
|
||||||
Password = password;
|
Password = password;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,10 @@
|
|||||||
using System;
|
namespace CryptoExchange.Net.Objects;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Objects
|
/// <summary>
|
||||||
|
/// An alias used by the exchange for an asset commonly known by another name
|
||||||
|
/// </summary>
|
||||||
|
public class AssetAlias
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// An alias used by the exchange for an asset commonly known by another name
|
|
||||||
/// </summary>
|
|
||||||
public class AssetAlias
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Alias type
|
|
||||||
/// </summary>
|
|
||||||
public AliasType Type { get; set; }
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The name of the asset on the exchange
|
/// The name of the asset on the exchange
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -25,26 +17,9 @@ namespace CryptoExchange.Net.Objects
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// ctor
|
/// ctor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public AssetAlias(string exchangeName, string commonName, AliasType type = AliasType.BothWays)
|
public AssetAlias(string exchangeName, string commonName)
|
||||||
{
|
{
|
||||||
ExchangeAssetName = exchangeName;
|
ExchangeAssetName = exchangeName;
|
||||||
CommonAssetName = commonName;
|
CommonAssetName = commonName;
|
||||||
Type = type;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Alias type
|
|
||||||
/// </summary>
|
|
||||||
public enum AliasType
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Translate both from and to exchange
|
|
||||||
/// </summary>
|
|
||||||
BothWays,
|
|
||||||
/// <summary>
|
|
||||||
/// Only translate when converting to exchange
|
|
||||||
/// </summary>
|
|
||||||
OnlyToExchange
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,12 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Objects
|
namespace CryptoExchange.Net.Objects;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Exchange configuration for asset aliases
|
||||||
|
/// </summary>
|
||||||
|
public class AssetAliasConfiguration
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Exchange configuration for asset aliases
|
|
||||||
/// </summary>
|
|
||||||
public class AssetAliasConfiguration
|
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Defined aliases
|
/// Defined aliases
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -23,22 +20,11 @@ namespace CryptoExchange.Net.Objects
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Map the common name to an exchange name for an asset. If there is no alias the input name is returned
|
/// Map the common name to an exchange name for an asset. If there is no alias the input name is returned
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string CommonToExchangeName(string commonName) => !AutoConvertEnabled ? commonName : Aliases.FirstOrDefault(x => x.CommonAssetName == commonName)?.ExchangeAssetName ?? commonName;
|
public string CommonToExchangeName(string commonName) => !AutoConvertEnabled ? commonName : Aliases.SingleOrDefault(x => x.CommonAssetName == commonName)?.ExchangeAssetName ?? commonName;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Map the exchange name to a common name for an asset. If there is no alias the input name is returned
|
/// Map the exchange name to a common name for an asset. If there is no alias the input name is returned
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string ExchangeToCommonName(string exchangeName)
|
public string ExchangeToCommonName(string exchangeName) => !AutoConvertEnabled ? exchangeName : Aliases.SingleOrDefault(x => x.ExchangeAssetName == exchangeName)?.CommonAssetName ?? exchangeName;
|
||||||
{
|
|
||||||
if (!AutoConvertEnabled)
|
|
||||||
return exchangeName;
|
|
||||||
|
|
||||||
var alias = Aliases.FirstOrDefault(x => x.ExchangeAssetName == exchangeName);
|
|
||||||
if (alias == null || alias.Type == AliasType.OnlyToExchange)
|
|
||||||
return exchangeName;
|
|
||||||
|
|
||||||
return alias.CommonAssetName;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Objects
|
namespace CryptoExchange.Net.Objects;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Async auto reset based on Stephen Toub`s implementation
|
||||||
|
/// https://devblogs.microsoft.com/pfxteam/building-async-coordination-primitives-part-2-asyncautoresetevent/
|
||||||
|
/// </summary>
|
||||||
|
public class AsyncResetEvent : IDisposable
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Async auto reset based on Stephen Toub`s implementation
|
|
||||||
/// https://devblogs.microsoft.com/pfxteam/building-async-coordination-primitives-part-2-asyncautoresetevent/
|
|
||||||
/// </summary>
|
|
||||||
public class AsyncResetEvent : IDisposable
|
|
||||||
{
|
|
||||||
private static readonly Task<bool> _completed = Task.FromResult(true);
|
private static readonly Task<bool> _completed = Task.FromResult(true);
|
||||||
private Queue<TaskCompletionSource<bool>> _waits = new Queue<TaskCompletionSource<bool>>();
|
private Queue<TaskCompletionSource<bool>> _waits = new Queue<TaskCompletionSource<bool>>();
|
||||||
private bool _signaled;
|
private bool _signaled;
|
||||||
@@ -106,15 +106,28 @@ namespace CryptoExchange.Net.Objects
|
|||||||
toRelease.TrySetResult(true);
|
toRelease.TrySetResult(true);
|
||||||
}
|
}
|
||||||
else if (!_signaled)
|
else if (!_signaled)
|
||||||
|
{
|
||||||
_signaled = true;
|
_signaled = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Dispose
|
/// Dispose
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Dispose(true);
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Dispose
|
||||||
|
/// </summary>
|
||||||
|
public void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (disposing)
|
||||||
{
|
{
|
||||||
_waits.Clear();
|
_waits.Clear();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
using CryptoExchange.Net.Interfaces;
|
using CryptoExchange.Net.Interfaces;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Objects
|
namespace CryptoExchange.Net.Objects;
|
||||||
|
|
||||||
|
internal class AuthTimeProvider : IAuthTimeProvider
|
||||||
{
|
{
|
||||||
internal class AuthTimeProvider : IAuthTimeProvider
|
|
||||||
{
|
|
||||||
public DateTime GetTime() => DateTime.UtcNow;
|
public DateTime GetTime() => DateTime.UtcNow;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Objects
|
namespace CryptoExchange.Net.Objects;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Comparer for byte order
|
||||||
|
/// </summary>
|
||||||
|
public class ByteOrderComparer : IComparer<byte[]>
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Comparer for byte order
|
|
||||||
/// </summary>
|
|
||||||
public class ByteOrderComparer : IComparer<byte[]>
|
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Compare function
|
/// Compare function
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -54,5 +54,4 @@ namespace CryptoExchange.Net.Objects
|
|||||||
// Compare lengths.
|
// Compare lengths.
|
||||||
return x.Length < y.Length ? -1 : 1;
|
return x.Length < y.Length ? -1 : 1;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using CryptoExchange.Net.SharedApis;
|
using CryptoExchange.Net.SharedApis;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
@@ -6,13 +6,13 @@ using System.Net;
|
|||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Objects
|
namespace CryptoExchange.Net.Objects;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The result of an operation
|
||||||
|
/// </summary>
|
||||||
|
public class CallResult
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// The result of an operation
|
|
||||||
/// </summary>
|
|
||||||
public class CallResult
|
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Static success result
|
/// Static success result
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -51,14 +51,14 @@ namespace CryptoExchange.Net.Objects
|
|||||||
{
|
{
|
||||||
return Success ? $"Success" : $"Error: {Error}";
|
return Success ? $"Success" : $"Error: {Error}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The result of an operation
|
/// The result of an operation
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T"></typeparam>
|
/// <typeparam name="T"></typeparam>
|
||||||
public class CallResult<T>: CallResult
|
public class CallResult<T>: CallResult
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The data returned by the call, only available when Success = true
|
/// The data returned by the call, only available when Success = true
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -140,12 +140,12 @@ namespace CryptoExchange.Net.Objects
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Copy the WebCallResult to a new data type
|
/// Copy the WebCallResult to a new data type
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="K">The new type</typeparam>
|
/// <typeparam name="TNew">The new type</typeparam>
|
||||||
/// <param name="data">The data of the new type</param>
|
/// <param name="data">The data of the new type</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public CallResult<K> As<K>([AllowNull] K data)
|
public CallResult<TNew> As<TNew>([AllowNull] TNew data)
|
||||||
{
|
{
|
||||||
return new CallResult<K>(data, OriginalData, Error);
|
return new CallResult<TNew>(data, OriginalData, Error);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -169,24 +169,24 @@ namespace CryptoExchange.Net.Objects
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Copy the CallResult to a new data type
|
/// Copy the CallResult to a new data type
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="K">The new type</typeparam>
|
/// <typeparam name="TNew">The new type</typeparam>
|
||||||
/// <param name="data">The data</param>
|
/// <param name="data">The data</param>
|
||||||
/// <param name="error">The error returned</param>
|
/// <param name="error">The error returned</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public CallResult<K> AsErrorWithData<K>(Error error, K data)
|
public CallResult<TNew> AsErrorWithData<TNew>(Error error, TNew data)
|
||||||
{
|
{
|
||||||
return new CallResult<K>(data, OriginalData, error);
|
return new CallResult<TNew>(data, OriginalData, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Copy the WebCallResult to a new data type
|
/// Copy the WebCallResult to a new data type
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="K">The new type</typeparam>
|
/// <typeparam name="TNew">The new type</typeparam>
|
||||||
/// <param name="error">The error to return</param>
|
/// <param name="error">The error to return</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public CallResult<K> AsError<K>(Error error)
|
public CallResult<TNew> AsError<TNew>(Error error)
|
||||||
{
|
{
|
||||||
return new CallResult<K>(default, OriginalData, error);
|
return new CallResult<TNew>(default, OriginalData, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -194,23 +194,18 @@ namespace CryptoExchange.Net.Objects
|
|||||||
{
|
{
|
||||||
return Success ? $"Success" : $"Error: {Error}";
|
return Success ? $"Success" : $"Error: {Error}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The result of a request
|
/// The result of a request
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class WebCallResult : CallResult
|
public class WebCallResult : CallResult
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The request http method
|
/// The request http method
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public HttpMethod? RequestMethod { get; set; }
|
public HttpMethod? RequestMethod { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// HTTP protocol version
|
|
||||||
/// </summary>
|
|
||||||
public Version? HttpVersion { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The headers sent with the request
|
/// The headers sent with the request
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -256,7 +251,6 @@ namespace CryptoExchange.Net.Objects
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public WebCallResult(
|
public WebCallResult(
|
||||||
HttpStatusCode? code,
|
HttpStatusCode? code,
|
||||||
Version? httpVersion,
|
|
||||||
KeyValuePair<string, string[]>[]? responseHeaders,
|
KeyValuePair<string, string[]>[]? responseHeaders,
|
||||||
TimeSpan? responseTime,
|
TimeSpan? responseTime,
|
||||||
string? originalData,
|
string? originalData,
|
||||||
@@ -268,7 +262,6 @@ namespace CryptoExchange.Net.Objects
|
|||||||
Error? error) : base(error)
|
Error? error) : base(error)
|
||||||
{
|
{
|
||||||
ResponseStatusCode = code;
|
ResponseStatusCode = code;
|
||||||
HttpVersion = httpVersion;
|
|
||||||
ResponseHeaders = responseHeaders;
|
ResponseHeaders = responseHeaders;
|
||||||
ResponseTime = responseTime;
|
ResponseTime = responseTime;
|
||||||
RequestId = requestId;
|
RequestId = requestId;
|
||||||
@@ -293,55 +286,55 @@ namespace CryptoExchange.Net.Objects
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public WebCallResult AsError(Error error)
|
public WebCallResult AsError(Error error)
|
||||||
{
|
{
|
||||||
return new WebCallResult(ResponseStatusCode, HttpVersion, ResponseHeaders, ResponseTime, OriginalData, RequestId, RequestUrl, RequestBody, RequestMethod, RequestHeaders, error);
|
return new WebCallResult(ResponseStatusCode, ResponseHeaders, ResponseTime, OriginalData, RequestId, RequestUrl, RequestBody, RequestMethod, RequestHeaders, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Copy the WebCallResult to a new data type
|
/// Copy the WebCallResult to a new data type
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="K">The new type</typeparam>
|
/// <typeparam name="TNew">The new type</typeparam>
|
||||||
/// <param name="data">The data of the new type</param>
|
/// <param name="data">The data of the new type</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public WebCallResult<K> As<K>([AllowNull] K data)
|
public WebCallResult<TNew> As<TNew>([AllowNull] TNew data)
|
||||||
{
|
{
|
||||||
return new WebCallResult<K>(ResponseStatusCode, HttpVersion, ResponseHeaders, ResponseTime, 0, null, RequestId, RequestUrl, RequestBody, RequestMethod, RequestHeaders, ResultDataSource.Server, data, Error);
|
return new WebCallResult<TNew>(ResponseStatusCode, ResponseHeaders, ResponseTime, 0, null, RequestId, RequestUrl, RequestBody, RequestMethod, RequestHeaders, ResultDataSource.Server, data, Error);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Copy the WebCallResult to an ExchangeWebResult of a new data type
|
/// Copy the WebCallResult to an ExchangeWebResult of a new data type
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="K">The new type</typeparam>
|
/// <typeparam name="TNew">The new type</typeparam>
|
||||||
/// <param name="exchange">The exchange</param>
|
/// <param name="exchange">The exchange</param>
|
||||||
/// <param name="tradeMode">Trade mode the result applies to</param>
|
/// <param name="tradeMode">Trade mode the result applies to</param>
|
||||||
/// <param name="data">The data</param>
|
/// <param name="data">The data</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public ExchangeWebResult<K> AsExchangeResult<K>(string exchange, TradingMode tradeMode, [AllowNull] K data)
|
public ExchangeWebResult<TNew> AsExchangeResult<TNew>(string exchange, TradingMode tradeMode, [AllowNull] TNew data)
|
||||||
{
|
{
|
||||||
return new ExchangeWebResult<K>(exchange, tradeMode, this.As<K>(data));
|
return new ExchangeWebResult<TNew>(exchange, tradeMode, this.As<TNew>(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Copy the WebCallResult to an ExchangeWebResult of a new data type
|
/// Copy the WebCallResult to an ExchangeWebResult of a new data type
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="K">The new type</typeparam>
|
/// <typeparam name="TNew">The new type</typeparam>
|
||||||
/// <param name="exchange">The exchange</param>
|
/// <param name="exchange">The exchange</param>
|
||||||
/// <param name="tradeModes">Trade modes the result applies to</param>
|
/// <param name="tradeModes">Trade modes the result applies to</param>
|
||||||
/// <param name="data">The data</param>
|
/// <param name="data">The data</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public ExchangeWebResult<K> AsExchangeResult<K>(string exchange, TradingMode[]? tradeModes, [AllowNull] K data)
|
public ExchangeWebResult<TNew> AsExchangeResult<TNew>(string exchange, TradingMode[]? tradeModes, [AllowNull] TNew data)
|
||||||
{
|
{
|
||||||
return new ExchangeWebResult<K>(exchange, tradeModes, this.As<K>(data));
|
return new ExchangeWebResult<TNew>(exchange, tradeModes, this.As<TNew>(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Copy the WebCallResult to a new data type
|
/// Copy the WebCallResult to a new data type
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="K">The new type</typeparam>
|
/// <typeparam name="TNew">The new type</typeparam>
|
||||||
/// <param name="error">The error returned</param>
|
/// <param name="error">The error returned</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public WebCallResult<K> AsError<K>(Error error)
|
public WebCallResult<TNew> AsError<TNew>(Error error)
|
||||||
{
|
{
|
||||||
return new WebCallResult<K>(ResponseStatusCode, HttpVersion, ResponseHeaders, ResponseTime, 0, null, RequestId, RequestUrl, RequestBody, RequestMethod, RequestHeaders, ResultDataSource.Server, default, error);
|
return new WebCallResult<TNew>(ResponseStatusCode, ResponseHeaders, ResponseTime, 0, null, RequestId, RequestUrl, RequestBody, RequestMethod, RequestHeaders, ResultDataSource.Server, default, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -349,24 +342,19 @@ namespace CryptoExchange.Net.Objects
|
|||||||
{
|
{
|
||||||
return (Success ? $"Success" : $"Error: {Error}") + $" in {ResponseTime}";
|
return (Success ? $"Success" : $"Error: {Error}") + $" in {ResponseTime}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The result of a request
|
/// The result of a request
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T"></typeparam>
|
/// <typeparam name="T"></typeparam>
|
||||||
public class WebCallResult<T>: CallResult<T>
|
public class WebCallResult<T>: CallResult<T>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The request http method
|
/// The request http method
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public HttpMethod? RequestMethod { get; set; }
|
public HttpMethod? RequestMethod { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// HTTP protocol version
|
|
||||||
/// </summary>
|
|
||||||
public Version? HttpVersion { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The headers sent with the request
|
/// The headers sent with the request
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -415,9 +403,21 @@ namespace CryptoExchange.Net.Objects
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a new result
|
/// Create a new result
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="code"></param>
|
||||||
|
/// <param name="responseHeaders"></param>
|
||||||
|
/// <param name="responseTime"></param>
|
||||||
|
/// <param name="responseLength"></param>
|
||||||
|
/// <param name="originalData"></param>
|
||||||
|
/// <param name="requestId"></param>
|
||||||
|
/// <param name="requestUrl"></param>
|
||||||
|
/// <param name="requestBody"></param>
|
||||||
|
/// <param name="requestMethod"></param>
|
||||||
|
/// <param name="requestHeaders"></param>
|
||||||
|
/// <param name="dataSource"></param>
|
||||||
|
/// <param name="data"></param>
|
||||||
|
/// <param name="error"></param>
|
||||||
public WebCallResult(
|
public WebCallResult(
|
||||||
HttpStatusCode? code,
|
HttpStatusCode? code,
|
||||||
Version? httpVersion,
|
|
||||||
KeyValuePair<string, string[]>[]? responseHeaders,
|
KeyValuePair<string, string[]>[]? responseHeaders,
|
||||||
TimeSpan? responseTime,
|
TimeSpan? responseTime,
|
||||||
long? responseLength,
|
long? responseLength,
|
||||||
@@ -431,7 +431,6 @@ namespace CryptoExchange.Net.Objects
|
|||||||
[AllowNull] T data,
|
[AllowNull] T data,
|
||||||
Error? error) : base(data, originalData, error)
|
Error? error) : base(data, originalData, error)
|
||||||
{
|
{
|
||||||
HttpVersion = httpVersion;
|
|
||||||
ResponseStatusCode = code;
|
ResponseStatusCode = code;
|
||||||
ResponseHeaders = responseHeaders;
|
ResponseHeaders = responseHeaders;
|
||||||
ResponseTime = responseTime;
|
ResponseTime = responseTime;
|
||||||
@@ -451,7 +450,7 @@ namespace CryptoExchange.Net.Objects
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public new WebCallResult AsDataless()
|
public new WebCallResult AsDataless()
|
||||||
{
|
{
|
||||||
return new WebCallResult(ResponseStatusCode, HttpVersion, ResponseHeaders, ResponseTime, OriginalData, RequestId, RequestUrl, RequestBody, RequestMethod, RequestHeaders, Error);
|
return new WebCallResult(ResponseStatusCode, ResponseHeaders, ResponseTime, OriginalData, RequestId, RequestUrl, RequestBody, RequestMethod, RequestHeaders, Error);
|
||||||
}
|
}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Copy as a dataless result
|
/// Copy as a dataless result
|
||||||
@@ -459,47 +458,47 @@ namespace CryptoExchange.Net.Objects
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public new WebCallResult AsDatalessError(Error error)
|
public new WebCallResult AsDatalessError(Error error)
|
||||||
{
|
{
|
||||||
return new WebCallResult(ResponseStatusCode, HttpVersion, ResponseHeaders, ResponseTime, OriginalData, RequestId, RequestUrl, RequestBody, RequestMethod, RequestHeaders, error);
|
return new WebCallResult(ResponseStatusCode, ResponseHeaders, ResponseTime, OriginalData, RequestId, RequestUrl, RequestBody, RequestMethod, RequestHeaders, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a new error result
|
/// Create a new error result
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="error">The error</param>
|
/// <param name="error">The error</param>
|
||||||
public WebCallResult(Error? error) : this(null, null, null, null, null, null, null, null, null, null, null, ResultDataSource.Server, default, error) { }
|
public WebCallResult(Error? error) : this(null, null, null, null, null, null, null, null, null, null, ResultDataSource.Server, default, error) { }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Copy the WebCallResult to a new data type
|
/// Copy the WebCallResult to a new data type
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="K">The new type</typeparam>
|
/// <typeparam name="TNew">The new type</typeparam>
|
||||||
/// <param name="data">The data of the new type</param>
|
/// <param name="data">The data of the new type</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public new WebCallResult<K> As<K>([AllowNull] K data)
|
public new WebCallResult<TNew> As<TNew>([AllowNull] TNew data)
|
||||||
{
|
{
|
||||||
return new WebCallResult<K>(ResponseStatusCode, HttpVersion, ResponseHeaders, ResponseTime, ResponseLength, OriginalData, RequestId, RequestUrl, RequestBody, RequestMethod, RequestHeaders, DataSource, data, Error);
|
return new WebCallResult<TNew>(ResponseStatusCode, ResponseHeaders, ResponseTime, ResponseLength, OriginalData, RequestId, RequestUrl, RequestBody, RequestMethod, RequestHeaders, DataSource, data, Error);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Copy the WebCallResult to a new data type
|
/// Copy the WebCallResult to a new data type
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="K">The new type</typeparam>
|
/// <typeparam name="TNew">The new type</typeparam>
|
||||||
/// <param name="error">The error returned</param>
|
/// <param name="error">The error returned</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public new WebCallResult<K> AsError<K>(Error error)
|
public new WebCallResult<TNew> AsError<TNew>(Error error)
|
||||||
{
|
{
|
||||||
return new WebCallResult<K>(ResponseStatusCode, HttpVersion, ResponseHeaders, ResponseTime, ResponseLength, OriginalData, RequestId, RequestUrl, RequestBody, RequestMethod, RequestHeaders, DataSource, default, error);
|
return new WebCallResult<TNew>(ResponseStatusCode, ResponseHeaders, ResponseTime, ResponseLength, OriginalData, RequestId, RequestUrl, RequestBody, RequestMethod, RequestHeaders, DataSource, default, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Copy the WebCallResult to a new data type
|
/// Copy the WebCallResult to a new data type
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="K">The new type</typeparam>
|
/// <typeparam name="TNew">The new type</typeparam>
|
||||||
/// <param name="data">The data</param>
|
/// <param name="data">The data</param>
|
||||||
/// <param name="error">The error returned</param>
|
/// <param name="error">The error returned</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public new WebCallResult<K> AsErrorWithData<K>(Error error, K data)
|
public new WebCallResult<TNew> AsErrorWithData<TNew>(Error error, TNew data)
|
||||||
{
|
{
|
||||||
return new WebCallResult<K>(ResponseStatusCode, HttpVersion, ResponseHeaders, ResponseTime, ResponseLength, OriginalData, RequestId, RequestUrl, RequestBody, RequestMethod, RequestHeaders, DataSource, data, error);
|
return new WebCallResult<TNew>(ResponseStatusCode, ResponseHeaders, ResponseTime, ResponseLength, OriginalData, RequestId, RequestUrl, RequestBody, RequestMethod, RequestHeaders, DataSource, data, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -527,41 +526,41 @@ namespace CryptoExchange.Net.Objects
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Copy the WebCallResult to an ExchangeWebResult of a new data type
|
/// Copy the WebCallResult to an ExchangeWebResult of a new data type
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="K">The new type</typeparam>
|
/// <typeparam name="TNew">The new type</typeparam>
|
||||||
/// <param name="exchange">The exchange</param>
|
/// <param name="exchange">The exchange</param>
|
||||||
/// <param name="tradeMode">Trade mode the result applies to</param>
|
/// <param name="tradeMode">Trade mode the result applies to</param>
|
||||||
/// <param name="data">Data</param>
|
/// <param name="data">Data</param>
|
||||||
/// <param name="nextPageToken">Next page token</param>
|
/// <param name="nextPageToken">Next page token</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public ExchangeWebResult<K> AsExchangeResult<K>(string exchange, TradingMode tradeMode, [AllowNull] K data, INextPageToken? nextPageToken = null)
|
public ExchangeWebResult<TNew> AsExchangeResult<TNew>(string exchange, TradingMode tradeMode, [AllowNull] TNew data, INextPageToken? nextPageToken = null)
|
||||||
{
|
{
|
||||||
return new ExchangeWebResult<K>(exchange, tradeMode, As<K>(data), nextPageToken);
|
return new ExchangeWebResult<TNew>(exchange, tradeMode, As<TNew>(data), nextPageToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Copy the WebCallResult to an ExchangeWebResult of a new data type
|
/// Copy the WebCallResult to an ExchangeWebResult of a new data type
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="K">The new type</typeparam>
|
/// <typeparam name="TNew">The new type</typeparam>
|
||||||
/// <param name="exchange">The exchange</param>
|
/// <param name="exchange">The exchange</param>
|
||||||
/// <param name="tradeModes">Trade modes the result applies to</param>
|
/// <param name="tradeModes">Trade modes the result applies to</param>
|
||||||
/// <param name="data">Data</param>
|
/// <param name="data">Data</param>
|
||||||
/// <param name="nextPageToken">Next page token</param>
|
/// <param name="nextPageToken">Next page token</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public ExchangeWebResult<K> AsExchangeResult<K>(string exchange, TradingMode[]? tradeModes, [AllowNull] K data, INextPageToken? nextPageToken = null)
|
public ExchangeWebResult<TNew> AsExchangeResult<TNew>(string exchange, TradingMode[]? tradeModes, [AllowNull] TNew data, INextPageToken? nextPageToken = null)
|
||||||
{
|
{
|
||||||
return new ExchangeWebResult<K>(exchange, tradeModes, As<K>(data), nextPageToken);
|
return new ExchangeWebResult<TNew>(exchange, tradeModes, As<TNew>(data), nextPageToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Copy the WebCallResult to an ExchangeWebResult with a specific error
|
/// Copy the WebCallResult to an ExchangeWebResult with a specific error
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="K">The new type</typeparam>
|
/// <typeparam name="TNew">The new type</typeparam>
|
||||||
/// <param name="exchange">The exchange</param>
|
/// <param name="exchange">The exchange</param>
|
||||||
/// <param name="error">The error returned</param>
|
/// <param name="error">The error returned</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public ExchangeWebResult<K> AsExchangeError<K>(string exchange, Error error)
|
public ExchangeWebResult<TNew> AsExchangeError<TNew>(string exchange, Error error)
|
||||||
{
|
{
|
||||||
return new ExchangeWebResult<K>(exchange, null, AsError<K>(error));
|
return new ExchangeWebResult<TNew>(exchange, null, AsError<TNew>(error));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -570,7 +569,7 @@ namespace CryptoExchange.Net.Objects
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
internal WebCallResult<T> Cached()
|
internal WebCallResult<T> Cached()
|
||||||
{
|
{
|
||||||
return new WebCallResult<T>(ResponseStatusCode, HttpVersion, ResponseHeaders, ResponseTime, ResponseLength, OriginalData, RequestId, RequestUrl, RequestBody, RequestMethod, RequestHeaders, ResultDataSource.Cache, Data, Error);
|
return new WebCallResult<T>(ResponseStatusCode, ResponseHeaders, ResponseTime, ResponseLength, OriginalData, RequestId, RequestUrl, RequestBody, RequestMethod, RequestHeaders, ResultDataSource.Cache, Data, Error);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -585,5 +584,4 @@ namespace CryptoExchange.Net.Objects
|
|||||||
|
|
||||||
return sb.ToString();
|
return sb.ToString();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
namespace CryptoExchange.Net.Objects
|
namespace CryptoExchange.Net.Objects;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Constants
|
||||||
|
/// </summary>
|
||||||
|
public class Constants
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Constants
|
|
||||||
/// </summary>
|
|
||||||
public class Constants
|
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Json content type header
|
/// Json content type header
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -17,5 +17,4 @@
|
|||||||
/// Placeholder key for when request body should be set to the value of this KVP
|
/// Placeholder key for when request body should be set to the value of this KVP
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const string BodyPlaceHolderKey = "_BODY_";
|
public const string BodyPlaceHolderKey = "_BODY_";
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
using CryptoExchange.Net.Attributes;
|
namespace CryptoExchange.Net.Objects;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Objects
|
/// <summary>
|
||||||
|
/// What to do when a request would exceed the rate limit
|
||||||
|
/// </summary>
|
||||||
|
public enum RateLimitingBehaviour
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// What to do when a request would exceed the rate limit
|
|
||||||
/// </summary>
|
|
||||||
public enum RateLimitingBehaviour
|
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Fail the request
|
/// Fail the request
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -15,13 +13,13 @@ namespace CryptoExchange.Net.Objects
|
|||||||
/// Wait till the request can be send
|
/// Wait till the request can be send
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Wait
|
Wait
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// What to do when a request would exceed the rate limit
|
/// What to do when a request would exceed the rate limit
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public enum RateLimitWindowType
|
public enum RateLimitWindowType
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A sliding window
|
/// A sliding window
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -38,13 +36,13 @@ namespace CryptoExchange.Net.Objects
|
|||||||
/// Decaying window
|
/// Decaying window
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Decay
|
Decay
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Where the parameters for a HttpMethod should be added in a request
|
/// Where the parameters for a HttpMethod should be added in a request
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public enum HttpMethodParameterPosition
|
public enum HttpMethodParameterPosition
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Parameters in body
|
/// Parameters in body
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -53,13 +51,13 @@ namespace CryptoExchange.Net.Objects
|
|||||||
/// Parameters in url
|
/// Parameters in url
|
||||||
/// </summary>
|
/// </summary>
|
||||||
InUri
|
InUri
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The format of the request body
|
/// The format of the request body
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public enum RequestBodyFormat
|
public enum RequestBodyFormat
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Form data
|
/// Form data
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -68,13 +66,13 @@ namespace CryptoExchange.Net.Objects
|
|||||||
/// Json
|
/// Json
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Json
|
Json
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tracker sync status
|
/// Tracker sync status
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public enum SyncStatus
|
public enum SyncStatus
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Not connected
|
/// Not connected
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -95,13 +93,13 @@ namespace CryptoExchange.Net.Objects
|
|||||||
/// Disposed
|
/// Disposed
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Disposed
|
Disposed
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Status of the order book
|
/// Status of the order book
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public enum OrderBookStatus
|
public enum OrderBookStatus
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Not connected
|
/// Not connected
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -130,13 +128,13 @@ namespace CryptoExchange.Net.Objects
|
|||||||
/// Disposed
|
/// Disposed
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Disposed
|
Disposed
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Order book entry type
|
/// Order book entry type
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public enum OrderBookEntryType
|
public enum OrderBookEntryType
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Ask
|
/// Ask
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -145,14 +143,14 @@ namespace CryptoExchange.Net.Objects
|
|||||||
/// Bid
|
/// Bid
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Bid
|
Bid
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Define how array parameters should be send
|
/// Define how array parameters should be send
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public enum ArrayParametersSerialization
|
public enum ArrayParametersSerialization
|
||||||
#pragma warning disable CS1570 // XML comment has badly formed XML
|
#pragma warning disable CS1570 // XML comment has badly formed XML
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Send as key=value1&key=value2
|
/// Send as key=value1&key=value2
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -167,13 +165,13 @@ namespace CryptoExchange.Net.Objects
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
JsonArray
|
JsonArray
|
||||||
#pragma warning restore CS1570 // XML comment has badly formed XML
|
#pragma warning restore CS1570 // XML comment has badly formed XML
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// How to round
|
/// How to round
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public enum RoundingType
|
public enum RoundingType
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Round down (flooring)
|
/// Round down (flooring)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -186,13 +184,13 @@ namespace CryptoExchange.Net.Objects
|
|||||||
/// Round up (ceil)
|
/// Round up (ceil)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Up
|
Up
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Type of the update
|
/// Type of the update
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public enum SocketUpdateType
|
public enum SocketUpdateType
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A update
|
/// A update
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -201,13 +199,13 @@ namespace CryptoExchange.Net.Objects
|
|||||||
/// A snapshot, generally send at the start of the connection
|
/// A snapshot, generally send at the start of the connection
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Snapshot
|
Snapshot
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Reconnect policy
|
/// Reconnect policy
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public enum ReconnectPolicy
|
public enum ReconnectPolicy
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Reconnect is disabled
|
/// Reconnect is disabled
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -220,13 +218,13 @@ namespace CryptoExchange.Net.Objects
|
|||||||
/// Backoff policy of 2^`reconnectAttempt`, where `reconnectAttempt` has a max value of 5
|
/// Backoff policy of 2^`reconnectAttempt`, where `reconnectAttempt` has a max value of 5
|
||||||
/// </summary>
|
/// </summary>
|
||||||
ExponentialBackoff
|
ExponentialBackoff
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The data source of the result
|
/// The data source of the result
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public enum ResultDataSource
|
public enum ResultDataSource
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// From server
|
/// From server
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -235,13 +233,13 @@ namespace CryptoExchange.Net.Objects
|
|||||||
/// From cache
|
/// From cache
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Cache
|
Cache
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Type of exchange
|
/// Type of exchange
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public enum ExchangeType
|
public enum ExchangeType
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Centralized
|
/// Centralized
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -250,13 +248,13 @@ namespace CryptoExchange.Net.Objects
|
|||||||
/// Decentralized
|
/// Decentralized
|
||||||
/// </summary>
|
/// </summary>
|
||||||
DEX
|
DEX
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Timeout behavior for queries
|
/// Timeout behavior for queries
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public enum TimeoutBehavior
|
public enum TimeoutBehavior
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Fail the request
|
/// Fail the request
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -265,33 +263,4 @@ namespace CryptoExchange.Net.Objects
|
|||||||
/// Mark the query as successful
|
/// Mark the query as successful
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Succeed
|
Succeed
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Subscription status
|
|
||||||
/// </summary>
|
|
||||||
public enum SubscriptionStatus
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Pending, waiting before (re)subscription can be started
|
|
||||||
/// </summary>
|
|
||||||
Pending,
|
|
||||||
/// <summary>
|
|
||||||
/// Currently (re)subscribing, will start producing updates soon if subscription is successful
|
|
||||||
/// </summary>
|
|
||||||
Subscribing,
|
|
||||||
/// <summary>
|
|
||||||
/// Subscribed and listening to updates
|
|
||||||
/// </summary>
|
|
||||||
Subscribed,
|
|
||||||
/// <summary>
|
|
||||||
/// Subscription is being closed and will stop producing updates
|
|
||||||
/// </summary>
|
|
||||||
Closing,
|
|
||||||
/// <summary>
|
|
||||||
/// Subscription is closed and will no long produce updates
|
|
||||||
/// </summary>
|
|
||||||
Closed
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+102
-104
@@ -1,14 +1,13 @@
|
|||||||
using CryptoExchange.Net.Objects.Errors;
|
using CryptoExchange.Net.Objects.Errors;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Objects
|
namespace CryptoExchange.Net.Objects;
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Base class for errors
|
|
||||||
/// </summary>
|
|
||||||
public abstract class Error
|
|
||||||
{
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Base class for errors
|
||||||
|
/// </summary>
|
||||||
|
public abstract class Error
|
||||||
|
{
|
||||||
private int? _code;
|
private int? _code;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The int error code the server returned; or the http status code int value if there was no error code.<br />
|
/// The int error code the server returned; or the http status code int value if there was no error code.<br />
|
||||||
@@ -81,60 +80,60 @@ namespace CryptoExchange.Net.Objects
|
|||||||
{
|
{
|
||||||
return ErrorCode != null ? $"[{GetType().Name}.{ErrorType}] {ErrorCode}: {Message ?? ErrorDescription}" : $"[{GetType().Name}.{ErrorType}] {Message ?? ErrorDescription}";
|
return ErrorCode != null ? $"[{GetType().Name}.{ErrorType}] {ErrorCode}: {Message ?? ErrorDescription}" : $"[{GetType().Name}.{ErrorType}] {Message ?? ErrorDescription}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Cant reach server error
|
/// Cant reach server error
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class CantConnectError : Error
|
public class CantConnectError : Error
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Default error info
|
/// Default error info
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected static readonly ErrorInfo _errorInfo = new ErrorInfo(ErrorType.UnableToConnect, false, "Can't connect to the server");
|
protected static readonly ErrorInfo errorInfo = new ErrorInfo(ErrorType.UnableToConnect, false, "Can't connect to the server");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// ctor
|
/// ctor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public CantConnectError() : base(null, _errorInfo, null) { }
|
public CantConnectError() : base(null, errorInfo, null) { }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// ctor
|
/// ctor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public CantConnectError(Exception? exception) : base(null, _errorInfo, exception) { }
|
public CantConnectError(Exception? exception) : base(null, errorInfo, exception) { }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// ctor
|
/// ctor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected CantConnectError(ErrorInfo info, Exception? exception) : base(null, info, exception) { }
|
protected CantConnectError(ErrorInfo info, Exception? exception) : base(null, info, exception) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// No api credentials provided while trying to access a private endpoint
|
/// No api credentials provided while trying to access a private endpoint
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class NoApiCredentialsError : Error
|
public class NoApiCredentialsError : Error
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Default error info
|
/// Default error info
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected static readonly ErrorInfo _errorInfo = new ErrorInfo(ErrorType.MissingCredentials, false, "No credentials provided for private endpoint");
|
protected static readonly ErrorInfo errorInfo = new ErrorInfo(ErrorType.MissingCredentials, false, "No credentials provided for private endpoint");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// ctor
|
/// ctor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public NoApiCredentialsError() : base(null, _errorInfo, null) { }
|
public NoApiCredentialsError() : base(null, errorInfo, null) { }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// ctor
|
/// ctor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected NoApiCredentialsError(ErrorInfo info, Exception? exception) : base(null, info, exception) { }
|
protected NoApiCredentialsError(ErrorInfo info, Exception? exception) : base(null, info, exception) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Error returned by the server
|
/// Error returned by the server
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class ServerError : Error
|
public class ServerError : Error
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// ctor
|
/// ctor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -151,91 +150,91 @@ namespace CryptoExchange.Net.Objects
|
|||||||
/// ctor
|
/// ctor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ServerError(string errorCode, ErrorInfo errorInfo, Exception? exception = null) : base(errorCode, errorInfo, exception) { }
|
public ServerError(string errorCode, ErrorInfo errorInfo, Exception? exception = null) : base(errorCode, errorInfo, exception) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Web error returned by the server
|
/// Web error returned by the server
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class WebError : Error
|
public class WebError : Error
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Default error info
|
/// Default error info
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected static readonly ErrorInfo _errorInfo = new ErrorInfo(ErrorType.NetworkError, true, "Failed to complete the request to the server due to a network error");
|
protected static readonly ErrorInfo errorInfo = new ErrorInfo(ErrorType.NetworkError, true, "Failed to complete the request to the server due to a network error");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// ctor
|
/// ctor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public WebError(string? message = null, Exception? exception = null) : base(null, _errorInfo with { Message = (message?.Length > 0 ? _errorInfo.Message + ": " + message : _errorInfo.Message) }, exception) { }
|
public WebError(string? message = null, Exception? exception = null) : base(null, errorInfo with { Message = (message?.Length > 0 ? errorInfo.Message + ": " + message : errorInfo.Message) }, exception) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Timeout error waiting for a response from the server
|
/// Timeout error waiting for a response from the server
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class TimeoutError : Error
|
public class TimeoutError : Error
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Default error info
|
/// Default error info
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected static readonly ErrorInfo _errorInfo = new ErrorInfo(ErrorType.Timeout, false, "Failed to receive a response from the server in time");
|
protected static readonly ErrorInfo errorInfo = new ErrorInfo(ErrorType.Timeout, false, "Failed to receive a response from the server in time");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// ctor
|
/// ctor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public TimeoutError(string? message = null, Exception? exception = null) : base(null, _errorInfo with { Message = (message?.Length > 0 ? _errorInfo.Message + ": " + message : _errorInfo.Message) }, exception) { }
|
public TimeoutError(string? message = null, Exception? exception = null) : base(null, errorInfo with { Message = (message?.Length > 0 ? errorInfo.Message + ": " + message : errorInfo.Message) }, exception) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Error while deserializing data
|
/// Error while deserializing data
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class DeserializeError : Error
|
public class DeserializeError : Error
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Default error info
|
/// Default error info
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected static readonly ErrorInfo _errorInfo = new ErrorInfo(ErrorType.DeserializationFailed, false, "Failed to deserialize data");
|
protected static readonly ErrorInfo errorInfo = new ErrorInfo(ErrorType.DeserializationFailed, false, "Failed to deserialize data");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// ctor
|
/// ctor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public DeserializeError(string? message = null, Exception? exception = null) : base(null, _errorInfo with { Message = (message?.Length > 0 ? _errorInfo.Message + ": " + message : _errorInfo.Message) }, exception) { }
|
public DeserializeError(string? message = null, Exception? exception = null) : base(null, errorInfo with { Message = (message?.Length > 0 ? errorInfo.Message + ": " + message : errorInfo.Message) }, exception) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// An invalid parameter has been provided
|
/// An invalid parameter has been provided
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class ArgumentError : Error
|
public class ArgumentError : Error
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Default error info for missing parameter
|
/// Default error info for missing parameter
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected static readonly ErrorInfo _missingInfo = new ErrorInfo(ErrorType.MissingParameter, false, "Missing parameter");
|
protected static readonly ErrorInfo missingInfo = new ErrorInfo(ErrorType.MissingParameter, false, "Missing parameter");
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Default error info for invalid parameter
|
/// Default error info for invalid parameter
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected static readonly ErrorInfo _invalidInfo = new ErrorInfo(ErrorType.InvalidParameter, false, "Invalid parameter");
|
protected static readonly ErrorInfo invalidInfo = new ErrorInfo(ErrorType.InvalidParameter, false, "Invalid parameter");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// ctor
|
/// ctor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static ArgumentError Missing(string parameterName, string? message = null) => new ArgumentError(_missingInfo with { Message = message == null ? $"{_missingInfo.Message} '{parameterName}'" : $"{_missingInfo.Message} '{parameterName}': {message}" }, null);
|
public static ArgumentError Missing(string parameterName, string? message = null) => new ArgumentError(missingInfo with { Message = message == null ? $"{missingInfo.Message} '{parameterName}'" : $"{missingInfo.Message} '{parameterName}': {message}" }, null);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// ctor
|
/// ctor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static ArgumentError Invalid(string parameterName, string message) => new ArgumentError(_invalidInfo with { Message = $"{_invalidInfo.Message} '{parameterName}': {message}" }, null);
|
public static ArgumentError Invalid(string parameterName, string message) => new ArgumentError(invalidInfo with { Message = $"{invalidInfo.Message} '{parameterName}': {message}" }, null);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// ctor
|
/// ctor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected ArgumentError(ErrorInfo info, Exception? exception) : base(null, info, exception) { }
|
protected ArgumentError(ErrorInfo info, Exception? exception) : base(null, info, exception) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Rate limit exceeded (client side)
|
/// Rate limit exceeded (client side)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class BaseRateLimitError : Error
|
public abstract class BaseRateLimitError : Error
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// When the request can be retried
|
/// When the request can be retried
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -245,89 +244,88 @@ namespace CryptoExchange.Net.Objects
|
|||||||
/// ctor
|
/// ctor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected BaseRateLimitError(ErrorInfo errorInfo, Exception? exception) : base(null, errorInfo, exception) { }
|
protected BaseRateLimitError(ErrorInfo errorInfo, Exception? exception) : base(null, errorInfo, exception) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Rate limit exceeded (client side)
|
/// Rate limit exceeded (client side)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class ClientRateLimitError : BaseRateLimitError
|
public class ClientRateLimitError : BaseRateLimitError
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Default error info
|
/// Default error info
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected static readonly ErrorInfo _errorInfo = new ErrorInfo(ErrorType.RateLimitRequest, false, "Client rate limit exceeded");
|
protected static readonly ErrorInfo errorInfo = new ErrorInfo(ErrorType.RateLimitRequest, false, "Client rate limit exceeded");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// ctor
|
/// ctor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ClientRateLimitError(string? message = null, Exception? exception = null) : base(_errorInfo with { Message = (message?.Length > 0 ? _errorInfo.Message + ": " + message : _errorInfo.Message) }, exception) { }
|
public ClientRateLimitError(string? message = null, Exception? exception = null) : base(errorInfo with { Message = (message?.Length > 0 ? errorInfo.Message + ": " + message : errorInfo.Message) }, exception) { }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// ctor
|
/// ctor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected ClientRateLimitError(ErrorInfo info, Exception? exception) : base(info, exception) { }
|
protected ClientRateLimitError(ErrorInfo info, Exception? exception) : base(info, exception) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Rate limit exceeded (server side)
|
/// Rate limit exceeded (server side)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class ServerRateLimitError : BaseRateLimitError
|
public class ServerRateLimitError : BaseRateLimitError
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Default error info
|
/// Default error info
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected static readonly ErrorInfo _errorInfo = new ErrorInfo(ErrorType.RateLimitRequest, false, "Server rate limit exceeded");
|
protected static readonly ErrorInfo errorInfo = new ErrorInfo(ErrorType.RateLimitRequest, false, "Server rate limit exceeded");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// ctor
|
/// ctor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ServerRateLimitError(string? message = null, Exception? exception = null) : base(_errorInfo with { Message = (message?.Length > 0 ? _errorInfo.Message + ": " + message : _errorInfo.Message) }, exception) { }
|
public ServerRateLimitError(string? message = null, Exception? exception = null) : base(errorInfo with { Message = (message?.Length > 0 ? errorInfo.Message + ": " + message : errorInfo.Message) }, exception) { }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// ctor
|
/// ctor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected ServerRateLimitError(ErrorInfo info, Exception? exception) : base(info, exception) { }
|
protected ServerRateLimitError(ErrorInfo info, Exception? exception) : base(info, exception) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Cancellation requested
|
/// Cancellation requested
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class CancellationRequestedError : Error
|
public class CancellationRequestedError : Error
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Default error info
|
/// Default error info
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected static readonly ErrorInfo _errorInfo = new ErrorInfo(ErrorType.CancellationRequested, false, "Cancellation requested");
|
protected static readonly ErrorInfo errorInfo = new ErrorInfo(ErrorType.CancellationRequested, false, "Cancellation requested");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// ctor
|
/// ctor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public CancellationRequestedError(Exception? exception = null) : base(null, _errorInfo, null) { }
|
public CancellationRequestedError(Exception? exception = null) : base(null, errorInfo, null) { }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// ctor
|
/// ctor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected CancellationRequestedError(ErrorInfo info, Exception? exception) : base(null, info, exception) { }
|
protected CancellationRequestedError(ErrorInfo info, Exception? exception) : base(null, info, exception) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Invalid operation requested
|
/// Invalid operation requested
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class InvalidOperationError : Error
|
public class InvalidOperationError : Error
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Default error info
|
/// Default error info
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected static readonly ErrorInfo _errorInfo = new ErrorInfo(ErrorType.InvalidOperation, false, "Operation invalid");
|
protected static readonly ErrorInfo errorInfo = new ErrorInfo(ErrorType.InvalidOperation, false, "Operation invalid");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// ctor
|
/// ctor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public InvalidOperationError(string message) : base(null, _errorInfo with { Message = message }, null) { }
|
public InvalidOperationError(string message) : base(null, errorInfo with { Message = message }, null) { }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// ctor
|
/// ctor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected InvalidOperationError(ErrorInfo info, Exception? exception) : base(null, info, exception) { }
|
protected InvalidOperationError(ErrorInfo info, Exception? exception) : base(null, info, exception) { }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,12 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Objects.Errors
|
namespace CryptoExchange.Net.Objects.Errors;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Error evaluator
|
||||||
|
/// </summary>
|
||||||
|
public class ErrorEvaluator
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Error evaluator
|
|
||||||
/// </summary>
|
|
||||||
public class ErrorEvaluator
|
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Error code
|
/// Error code
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -36,5 +34,4 @@ namespace CryptoExchange.Net.Objects.Errors
|
|||||||
ErrorCodes = errorCodes;
|
ErrorCodes = errorCodes;
|
||||||
ErrorTypeEvaluator = errorTypeEvaluator;
|
ErrorTypeEvaluator = errorTypeEvaluator;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user