From 7763d1a4e82f86282fc00825416f914b96b0c89b Mon Sep 17 00:00:00 2001 From: Jkorf Date: Mon, 23 Dec 2024 14:59:59 +0100 Subject: [PATCH] Update CryptoExchange.Net version to 8.5.0, added SetOptions on clients, added setting of DefaultProxyCredentials to CredentialCache.DefaultCredentials on the DI http client, improved websocket disconnect detection, updated dotnet versions to 9.0 --- .github/workflows/dotnet.yml | 2 +- ByBit.Net/Bybit.Net.csproj | 2 +- ByBit.Net/Clients/BybitRestClient.cs | 10 ++++++++++ ByBit.Net/Clients/BybitSocketClient.cs | 15 +++++++++++++++ .../BybitSocketClientDerivativesPublicApi.cs | 14 +++++++++++++- .../ContractApi/BybitSocketClientContractApi.cs | 14 +++++++++++++- .../BybitSocketClientUnifiedMarginApi.cs | 14 +++++++++++++- .../SpotApi/v3/BybitSocketClientSpotApiV3.cs | 14 +++++++++++++- .../Clients/V5/BybitSocketClientInverseApi.cs | 14 +++++++++++++- .../Clients/V5/BybitSocketClientLinearApi.cs | 14 +++++++++++++- .../Clients/V5/BybitSocketClientOptionApi.cs | 14 +++++++++++++- .../Clients/V5/BybitSocketClientPrivateApi.cs | 16 ++++++++++++++-- ByBit.Net/Clients/V5/BybitSocketClientSpotApi.cs | 14 +++++++++++++- .../ServiceCollectionExtensions.cs | 1 + ByBit.Net/Interfaces/Clients/IBybitRestClient.cs | 7 +++++++ .../Interfaces/Clients/IBybitSocketClient.cs | 7 +++++++ .../Objects/Sockets/Queries/BybitPingQuery.cs | 2 ++ Bybit.UnitTests/Bybit.UnitTests.csproj | 2 +- 18 files changed, 163 insertions(+), 13 deletions(-) diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index 53dfbca3..53d08e4e 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -16,7 +16,7 @@ jobs: - name: Setup .NET uses: actions/setup-dotnet@v1 with: - dotnet-version: 8.0.x + dotnet-version: 9.0.x - name: Set GitHub package source run: dotnet nuget add source --username JKorf --password ${{ secrets.GITHUB_TOKEN }} --store-password-in-clear-text --name github "https://nuget.pkg.github.com/JKorf/index.json" - name: Restore dependencies diff --git a/ByBit.Net/Bybit.Net.csproj b/ByBit.Net/Bybit.Net.csproj index 8f0e2038..ea43aeef 100644 --- a/ByBit.Net/Bybit.Net.csproj +++ b/ByBit.Net/Bybit.Net.csproj @@ -48,7 +48,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/ByBit.Net/Clients/BybitRestClient.cs b/ByBit.Net/Clients/BybitRestClient.cs index ef95bd7f..4b735a48 100644 --- a/ByBit.Net/Clients/BybitRestClient.cs +++ b/ByBit.Net/Clients/BybitRestClient.cs @@ -12,6 +12,7 @@ using Microsoft.Extensions.Logging; using CryptoExchange.Net.Clients; using Microsoft.Extensions.Options; +using CryptoExchange.Net.Objects.Options; namespace Bybit.Net.Clients { @@ -56,6 +57,15 @@ public BybitRestClient(HttpClient? httpClient, ILoggerFactory? loggerFactory, IO #endregion + /// + public void SetOptions(UpdateOptions options) + { + SpotApiV3.SetOptions(options); + CopyTradingApi.SetOptions(options); + DerivativesApi.SetOptions(options); + V5Api.SetOptions(options); + } + /// /// Set the default options to be used when creating new clients /// diff --git a/ByBit.Net/Clients/BybitSocketClient.cs b/ByBit.Net/Clients/BybitSocketClient.cs index 35fc312e..d62103f2 100644 --- a/ByBit.Net/Clients/BybitSocketClient.cs +++ b/ByBit.Net/Clients/BybitSocketClient.cs @@ -15,6 +15,7 @@ using Bybit.Net.Clients.SpotApi.v3; using CryptoExchange.Net.Clients; using Microsoft.Extensions.Options; +using CryptoExchange.Net.Objects.Options; namespace Bybit.Net.Clients { @@ -71,6 +72,20 @@ public BybitSocketClient(IOptions options, ILoggerFactory? l V5PrivateApi = AddApiClient(new BybitSocketClientPrivateApi(_logger, options.Value)); } + /// + public void SetOptions(UpdateOptions options) + { + SpotV3Api.SetOptions(options); + DerivativesApi.SetOptions(options); + UnifiedMarginApi.SetOptions(options); + ContractApi.SetOptions(options); + V5SpotApi.SetOptions(options); + V5InverseApi.SetOptions(options); + V5LinearApi.SetOptions(options); + V5OptionsApi.SetOptions(options); + V5PrivateApi.SetOptions(options); + } + /// /// Set the default options to be used when creating new clients /// diff --git a/ByBit.Net/Clients/DerivativesApi/BybitSocketClientDerivativesPublicApi.cs b/ByBit.Net/Clients/DerivativesApi/BybitSocketClientDerivativesPublicApi.cs index 47f80b99..0bb05dfc 100644 --- a/ByBit.Net/Clients/DerivativesApi/BybitSocketClientDerivativesPublicApi.cs +++ b/ByBit.Net/Clients/DerivativesApi/BybitSocketClientDerivativesPublicApi.cs @@ -40,7 +40,19 @@ internal BybitSocketClientDerivativesPublicApi(ILogger log, BybitSocketOptions o UnhandledMessageExpected = true; KeepAliveInterval = TimeSpan.Zero; - RegisterPeriodicQuery("Heartbeat", TimeSpan.FromSeconds(20), x => new BybitQuery("ping", null), x => { }); + RegisterPeriodicQuery( + "Heartbeat", + TimeSpan.FromSeconds(20), + x => new BybitQuery("ping", null) { RequestTimeout = TimeSpan.FromSeconds(5) }, + (connection, result) => + { + if (result.Error?.Message.Equals("Query timeout") == true) + { + // Ping timeout, reconnect + _logger.LogWarning("[Sckt {SocketId}] Ping response timeout, reconnecting", connection.SocketId); + _ = connection.TriggerReconnectAsync(); + } + }); } /// diff --git a/ByBit.Net/Clients/DerivativesApi/ContractApi/BybitSocketClientContractApi.cs b/ByBit.Net/Clients/DerivativesApi/ContractApi/BybitSocketClientContractApi.cs index 67e6c231..ab73c55b 100644 --- a/ByBit.Net/Clients/DerivativesApi/ContractApi/BybitSocketClientContractApi.cs +++ b/ByBit.Net/Clients/DerivativesApi/ContractApi/BybitSocketClientContractApi.cs @@ -36,7 +36,19 @@ internal BybitSocketClientContractApi(ILogger log, BybitSocketOptions options) UnhandledMessageExpected = true; KeepAliveInterval = TimeSpan.Zero; - RegisterPeriodicQuery("Heartbeat", TimeSpan.FromSeconds(20), x => new BybitQuery("ping", null), x => { }); + RegisterPeriodicQuery( + "Heartbeat", + TimeSpan.FromSeconds(20), + x => new BybitQuery("ping", null) { RequestTimeout = TimeSpan.FromSeconds(5) }, + (connection, result) => + { + if (result.Error?.Message.Equals("Query timeout") == true) + { + // Ping timeout, reconnect + _logger.LogWarning("[Sckt {SocketId}] Ping response timeout, reconnecting", connection.SocketId); + _ = connection.TriggerReconnectAsync(); + } + }); } /// diff --git a/ByBit.Net/Clients/DerivativesApi/UnifiedMarginApi/BybitSocketClientUnifiedMarginApi.cs b/ByBit.Net/Clients/DerivativesApi/UnifiedMarginApi/BybitSocketClientUnifiedMarginApi.cs index 5fa9d9be..118a3dae 100644 --- a/ByBit.Net/Clients/DerivativesApi/UnifiedMarginApi/BybitSocketClientUnifiedMarginApi.cs +++ b/ByBit.Net/Clients/DerivativesApi/UnifiedMarginApi/BybitSocketClientUnifiedMarginApi.cs @@ -38,7 +38,19 @@ internal BybitSocketClientUnifiedMarginApi(ILogger log, BybitSocketOptions optio { KeepAliveInterval = TimeSpan.Zero; - RegisterPeriodicQuery("Heartbeat", TimeSpan.FromSeconds(20), x => new BybitPingQuery(), x => { }); + RegisterPeriodicQuery( + "Heartbeat", + TimeSpan.FromSeconds(20), + x => new BybitPingQuery(), + (connection, result) => + { + if (result.Error?.Message.Equals("Query timeout") == true) + { + // Ping timeout, reconnect + _logger.LogWarning("[Sckt {SocketId}] Ping response timeout, reconnecting", connection.SocketId); + _ = connection.TriggerReconnectAsync(); + } + }); } /// diff --git a/ByBit.Net/Clients/SpotApi/v3/BybitSocketClientSpotApiV3.cs b/ByBit.Net/Clients/SpotApi/v3/BybitSocketClientSpotApiV3.cs index 7dd9822b..e0f98310 100644 --- a/ByBit.Net/Clients/SpotApi/v3/BybitSocketClientSpotApiV3.cs +++ b/ByBit.Net/Clients/SpotApi/v3/BybitSocketClientSpotApiV3.cs @@ -34,7 +34,19 @@ internal BybitSocketClientSpotApiV3(ILogger logger, BybitSocketOptions options) { KeepAliveInterval = TimeSpan.Zero; - RegisterPeriodicQuery("Heartbeat", TimeSpan.FromSeconds(20), x => new BybitQuery("ping", null), x => { }); + RegisterPeriodicQuery( + "Heartbeat", + TimeSpan.FromSeconds(20), + x => new BybitQuery("ping", null) { RequestTimeout = TimeSpan.FromSeconds(5) }, + (connection, result) => + { + if (result.Error?.Message.Equals("Query timeout") == true) + { + // Ping timeout, reconnect + _logger.LogWarning("[Sckt {SocketId}] Ping response timeout, reconnecting", connection.SocketId); + _ = connection.TriggerReconnectAsync(); + } + }); } /// diff --git a/ByBit.Net/Clients/V5/BybitSocketClientInverseApi.cs b/ByBit.Net/Clients/V5/BybitSocketClientInverseApi.cs index e34d3ce0..ab4582bd 100644 --- a/ByBit.Net/Clients/V5/BybitSocketClientInverseApi.cs +++ b/ByBit.Net/Clients/V5/BybitSocketClientInverseApi.cs @@ -26,7 +26,19 @@ internal partial class BybitSocketClientInverseApi : BybitSocketClientBaseApi, I internal BybitSocketClientInverseApi(ILogger log, BybitSocketOptions options) : base(log, options, "/v5/public/inverse") { - RegisterPeriodicQuery("Heartbeat", TimeSpan.FromSeconds(20), x => new BybitQuery("ping", null), x => { }); + RegisterPeriodicQuery( + "Heartbeat", + TimeSpan.FromSeconds(20), + x => new BybitQuery("ping", null) { RequestTimeout = TimeSpan.FromSeconds(5) }, + (connection, result) => + { + if (result.Error?.Message.Equals("Query timeout") == true) + { + // Ping timeout, reconnect + _logger.LogWarning("[Sckt {SocketId}] Ping response timeout, reconnecting", connection.SocketId); + _ = connection.TriggerReconnectAsync(); + } + }); } public IBybitSocketClientInverseApiShared SharedClient => this; diff --git a/ByBit.Net/Clients/V5/BybitSocketClientLinearApi.cs b/ByBit.Net/Clients/V5/BybitSocketClientLinearApi.cs index cc3a7a8d..f4f2f232 100644 --- a/ByBit.Net/Clients/V5/BybitSocketClientLinearApi.cs +++ b/ByBit.Net/Clients/V5/BybitSocketClientLinearApi.cs @@ -26,7 +26,19 @@ internal partial class BybitSocketClientLinearApi : BybitSocketClientBaseApi, IB internal BybitSocketClientLinearApi(ILogger log, BybitSocketOptions options) : base(log, options, "/v5/public/linear") { - RegisterPeriodicQuery("Heartbeat", TimeSpan.FromSeconds(20), x => new BybitQuery("ping", null), x => { }); + RegisterPeriodicQuery( + "Heartbeat", + TimeSpan.FromSeconds(20), + x => new BybitQuery("ping", null) { RequestTimeout = TimeSpan.FromSeconds(5) }, + (connection, result) => + { + if (result.Error?.Message.Equals("Query timeout") == true) + { + // Ping timeout, reconnect + _logger.LogWarning("[Sckt {SocketId}] Ping response timeout, reconnecting", connection.SocketId); + _ = connection.TriggerReconnectAsync(); + } + }); } public IBybitSocketClientLinearApiShared SharedClient => this; diff --git a/ByBit.Net/Clients/V5/BybitSocketClientOptionApi.cs b/ByBit.Net/Clients/V5/BybitSocketClientOptionApi.cs index c5e5b021..33ca15b3 100644 --- a/ByBit.Net/Clients/V5/BybitSocketClientOptionApi.cs +++ b/ByBit.Net/Clients/V5/BybitSocketClientOptionApi.cs @@ -30,7 +30,19 @@ internal class BybitSocketClientOptionApi : BybitSocketClientBaseApi, IBybitSock internal BybitSocketClientOptionApi(ILogger log, BybitSocketOptions options) : base(log, options, "/v5/public/option") { - RegisterPeriodicQuery("Heartbeat", TimeSpan.FromSeconds(20), x => new BybitPingQuery(), x => { }); + RegisterPeriodicQuery( + "Heartbeat", + TimeSpan.FromSeconds(20), + x => new BybitPingQuery(), + (connection, result) => + { + if (result.Error?.Message.Equals("Query timeout") == true) + { + // Ping timeout, reconnect + _logger.LogWarning("[Sckt {SocketId}] Ping response timeout, reconnecting", connection.SocketId); + _ = connection.TriggerReconnectAsync(); + } + }); } /// diff --git a/ByBit.Net/Clients/V5/BybitSocketClientPrivateApi.cs b/ByBit.Net/Clients/V5/BybitSocketClientPrivateApi.cs index e192a544..8707f2b8 100644 --- a/ByBit.Net/Clients/V5/BybitSocketClientPrivateApi.cs +++ b/ByBit.Net/Clients/V5/BybitSocketClientPrivateApi.cs @@ -40,7 +40,19 @@ internal BybitSocketClientPrivateApi(ILogger logger, BybitSocketOptions options) _referer = !string.IsNullOrEmpty(options.Referer) ? options.Referer! : "Zx000356"; - RegisterPeriodicQuery("Heartbeat", options.V5Options.PingInterval, GetPingQuery, x => { }); + RegisterPeriodicQuery( + "Heartbeat", + options.V5Options.PingInterval, + GetPingQuery, + (connection, result) => + { + if (result.Error?.Message.Equals("Query timeout") == true) + { + // Ping timeout, reconnect + _logger.LogWarning("[Sckt {SocketId}] Ping response timeout, reconnecting", connection.SocketId); + _ = connection.TriggerReconnectAsync(); + } + }); SetDedicatedConnection(BaseAddress.AppendPath("/v5/trade"), true); } @@ -49,7 +61,7 @@ private Query GetPingQuery(SocketConnection connection) { if (connection.ConnectionUri.AbsolutePath.EndsWith("private")) { - return new BybitQuery("ping", null); + return new BybitQuery("ping", null) { RequestTimeout = TimeSpan.FromSeconds(5) }; } else { diff --git a/ByBit.Net/Clients/V5/BybitSocketClientSpotApi.cs b/ByBit.Net/Clients/V5/BybitSocketClientSpotApi.cs index 81671567..7e0b5e72 100644 --- a/ByBit.Net/Clients/V5/BybitSocketClientSpotApi.cs +++ b/ByBit.Net/Clients/V5/BybitSocketClientSpotApi.cs @@ -27,7 +27,19 @@ internal partial class BybitSocketClientSpotApi : BybitSocketClientBaseApi, IByb internal BybitSocketClientSpotApi(ILogger logger, BybitSocketOptions options) : base(logger, options, "/v5/public/spot") { - RegisterPeriodicQuery("Heartbeat", TimeSpan.FromSeconds(20), x => new BybitQuery("ping", null), x => { }); + RegisterPeriodicQuery( + "Heartbeat", + TimeSpan.FromSeconds(20), + x => new BybitQuery("ping", null) { RequestTimeout = TimeSpan.FromSeconds(5) }, + (connection, result) => + { + if (result.Error?.Message.Equals("Query timeout") == true) + { + // Ping timeout, reconnect + _logger.LogWarning("[Sckt {SocketId}] Ping response timeout, reconnecting", connection.SocketId); + _ = connection.TriggerReconnectAsync(); + } + }); } /// diff --git a/ByBit.Net/ExtensionMethods/ServiceCollectionExtensions.cs b/ByBit.Net/ExtensionMethods/ServiceCollectionExtensions.cs index cb2a93d1..870e32a1 100644 --- a/ByBit.Net/ExtensionMethods/ServiceCollectionExtensions.cs +++ b/ByBit.Net/ExtensionMethods/ServiceCollectionExtensions.cs @@ -112,6 +112,7 @@ private static IServiceCollection AddBybitCore( try { handler.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate; + handler.DefaultProxyCredentials = CredentialCache.DefaultCredentials; } catch (PlatformNotSupportedException) { } diff --git a/ByBit.Net/Interfaces/Clients/IBybitRestClient.cs b/ByBit.Net/Interfaces/Clients/IBybitRestClient.cs index e1cf8b19..3451cafc 100644 --- a/ByBit.Net/Interfaces/Clients/IBybitRestClient.cs +++ b/ByBit.Net/Interfaces/Clients/IBybitRestClient.cs @@ -3,6 +3,7 @@ using Bybit.Net.Interfaces.Clients.SpotApi.v3; using CryptoExchange.Net.Authentication; using CryptoExchange.Net.Interfaces; +using CryptoExchange.Net.Objects.Options; namespace Bybit.Net.Interfaces.Clients { @@ -30,6 +31,12 @@ public interface IBybitRestClient: IRestClient /// V5.IBybitRestClientApi V5Api { get; } + /// + /// Update specific options + /// + /// Options to update. Only specific options are changable after the client has been created + void SetOptions(UpdateOptions options); + /// /// Set the API credentials for this client. All Api clients in this client will use the new credentials, regardless of earlier set options. /// diff --git a/ByBit.Net/Interfaces/Clients/IBybitSocketClient.cs b/ByBit.Net/Interfaces/Clients/IBybitSocketClient.cs index 8c81e754..3f6aa2b2 100644 --- a/ByBit.Net/Interfaces/Clients/IBybitSocketClient.cs +++ b/ByBit.Net/Interfaces/Clients/IBybitSocketClient.cs @@ -5,6 +5,7 @@ using Bybit.Net.Interfaces.Clients.V5; using CryptoExchange.Net.Authentication; using CryptoExchange.Net.Interfaces; +using CryptoExchange.Net.Objects.Options; namespace Bybit.Net.Interfaces.Clients { @@ -50,6 +51,12 @@ public interface IBybitSocketClient : ISocketClient /// public IBybitSocketClientPrivateApi V5PrivateApi { get; } + /// + /// Update specific options + /// + /// Options to update. Only specific options are changable after the client has been created + void SetOptions(UpdateOptions options); + /// /// Set the API credentials for this client. All Api clients in this client will use the new credentials, regardless of earlier set options. /// diff --git a/ByBit.Net/Objects/Sockets/Queries/BybitPingQuery.cs b/ByBit.Net/Objects/Sockets/Queries/BybitPingQuery.cs index 3898cce9..911c5714 100644 --- a/ByBit.Net/Objects/Sockets/Queries/BybitPingQuery.cs +++ b/ByBit.Net/Objects/Sockets/Queries/BybitPingQuery.cs @@ -1,5 +1,6 @@ using CryptoExchange.Net; using CryptoExchange.Net.Sockets; +using System; using System.Collections.Generic; namespace Bybit.Net.Objects.Sockets.Queries @@ -10,6 +11,7 @@ internal class BybitPingQuery : Query public BybitPingQuery() : base(new BybitRequestMessage { RequestId = ExchangeHelpers.NextId().ToString(), Operation = "ping", Args = null }, false, 1) { + RequestTimeout = TimeSpan.FromSeconds(5); ListenerIdentifiers = new HashSet() { "pong" }; } } diff --git a/Bybit.UnitTests/Bybit.UnitTests.csproj b/Bybit.UnitTests/Bybit.UnitTests.csproj index 691d866a..9ebbb812 100644 --- a/Bybit.UnitTests/Bybit.UnitTests.csproj +++ b/Bybit.UnitTests/Bybit.UnitTests.csproj @@ -1,7 +1,7 @@  - net8.0 + net9.0 false