1
0
mirror of https://github.com/JKorf/CryptoExchange.Net synced 2026-04-07 18:21:30 +00:00

Updated SetOptions logic to allow calling on client without credentials

This commit is contained in:
JKorf 2026-03-25 21:06:54 +01:00
parent 54b15b75d3
commit aab30e05f0
9 changed files with 157 additions and 31 deletions

View File

@ -1,4 +1,5 @@
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.UnitTests.TestImplementations; using CryptoExchange.Net.UnitTests.TestImplementations;
using NUnit.Framework; using NUnit.Framework;
@ -54,6 +55,63 @@ namespace CryptoExchange.Net.UnitTests
Assert.That(options.ApiCredentials.Secret == "456"); Assert.That(options.ApiCredentials.Secret == "456");
} }
[Test]
public void TestSetOptionsRest()
{
var client = new TestRestClient();
client.SetOptions(new UpdateOptions
{
RequestTimeout = TimeSpan.FromSeconds(2),
Proxy = new ApiProxy("http://testproxy", 1234)
});
Assert.That(client.Api1.ClientOptions.Proxy, Is.Not.Null);
Assert.That(client.Api1.ClientOptions.Proxy.Host, Is.EqualTo("http://testproxy"));
Assert.That(client.Api1.ClientOptions.Proxy.Port, Is.EqualTo(1234));
Assert.That(client.Api1.ClientOptions.RequestTimeout, Is.EqualTo(TimeSpan.FromSeconds(2)));
}
[Test]
public void TestSetOptionsRestWithCredentials()
{
var client = new TestRestClient();
client.SetOptions(new UpdateOptions<HMACCredential>
{
ApiCredentials = new HMACCredential("123", "456"),
RequestTimeout = TimeSpan.FromSeconds(2),
Proxy = new ApiProxy("http://testproxy", 1234)
});
Assert.That(client.Api1.ApiCredentials, Is.Not.Null);
Assert.That(client.Api1.ApiCredentials.Key, Is.EqualTo("123"));
Assert.That(client.Api1.ClientOptions.Proxy, Is.Not.Null);
Assert.That(client.Api1.ClientOptions.Proxy.Host, Is.EqualTo("http://testproxy"));
Assert.That(client.Api1.ClientOptions.Proxy.Port, Is.EqualTo(1234));
Assert.That(client.Api1.ClientOptions.RequestTimeout, Is.EqualTo(TimeSpan.FromSeconds(2)));
}
[Test]
public void TestWhenUpdatingSettingsExistingClientsAreNotAffected()
{
TestClientOptions.Default = new TestClientOptions
{
ApiCredentials = new HMACCredential("111", "222"),
RequestTimeout = TimeSpan.FromSeconds(1),
};
var client1 = new TestRestClient();
Assert.That(client1.ClientOptions.RequestTimeout, Is.EqualTo(TimeSpan.FromSeconds(1)));
Assert.That(client1.ClientOptions.ApiCredentials.Key, Is.EqualTo("111"));
TestClientOptions.Default.ApiCredentials = new HMACCredential("333", "444");
TestClientOptions.Default.RequestTimeout = TimeSpan.FromSeconds(2);
var client2 = new TestRestClient();
Assert.That(client2.ClientOptions.RequestTimeout, Is.EqualTo(TimeSpan.FromSeconds(2)));
Assert.That(client2.ClientOptions.ApiCredentials.Key, Is.EqualTo("333"));
}
} }
public class TestClientOptions: RestExchangeOptions<TestEnvironment, HMACCredential> public class TestClientOptions: RestExchangeOptions<TestEnvironment, HMACCredential>

View File

@ -23,7 +23,7 @@ using CryptoExchange.Net.Converters.MessageParsing.DynamicConverters;
namespace CryptoExchange.Net.UnitTests.TestImplementations namespace CryptoExchange.Net.UnitTests.TestImplementations
{ {
public class TestRestClient: BaseRestClient public class TestRestClient: BaseRestClient<TestEnvironment, HMACCredential>
{ {
public TestRestApi1Client Api1 { get; } public TestRestApi1Client Api1 { get; }
public TestRestApi2Client Api2 { get; } public TestRestApi2Client Api2 { get; }
@ -37,8 +37,8 @@ namespace CryptoExchange.Net.UnitTests.TestImplementations
{ {
Initialize(options.Value); Initialize(options.Value);
Api1 = new TestRestApi1Client(options.Value); Api1 = AddApiClient(new TestRestApi1Client(options.Value));
Api2 = new TestRestApi2Client(options.Value); Api2 = AddApiClient(new TestRestApi2Client(options.Value));
} }
public void SetResponse(string responseData, out IRequest requestObj) public void SetResponse(string responseData, out IRequest requestObj)

View File

@ -14,6 +14,11 @@ namespace CryptoExchange.Net.Clients
/// </summary> /// </summary>
public abstract class BaseRestClient : BaseClient, IRestClient public abstract class BaseRestClient : BaseClient, IRestClient
{ {
/// <summary>
/// Api clients in this client
/// </summary>
internal new List<RestApiClient> ApiClients => base.ApiClients.OfType<RestApiClient>().ToList();
/// <inheritdoc /> /// <inheritdoc />
public int TotalRequestsMade => ApiClients.OfType<RestApiClient>().Sum(s => s.TotalRequestsMade); public int TotalRequestsMade => ApiClients.OfType<RestApiClient>().Sum(s => s.TotalRequestsMade);
@ -29,6 +34,14 @@ namespace CryptoExchange.Net.Clients
LibraryHelpers.StaticLogger = loggerFactory?.CreateLogger("CryptoExchange"); LibraryHelpers.StaticLogger = loggerFactory?.CreateLogger("CryptoExchange");
} }
/// <summary>
/// Update options
/// </summary>
public virtual void SetOptions(UpdateOptions options)
{
foreach (var apiClient in ApiClients)
apiClient.SetOptions(options);
}
} }
/// <inheritdoc /> /// <inheritdoc />
@ -41,6 +54,11 @@ namespace CryptoExchange.Net.Clients
/// </summary> /// </summary>
internal new List<RestApiClient<TEnvironment, TApiCredentials>> ApiClients => base.ApiClients.OfType<RestApiClient<TEnvironment, TApiCredentials>>().ToList(); internal new List<RestApiClient<TEnvironment, TApiCredentials>> ApiClients => base.ApiClients.OfType<RestApiClient<TEnvironment, TApiCredentials>>().ToList();
/// <summary>
/// Provided client options
/// </summary>
public new RestExchangeOptions<TEnvironment, TApiCredentials> ClientOptions => (RestExchangeOptions<TEnvironment, TApiCredentials>)base.ClientOptions;
/// <summary> /// <summary>
/// ctor /// ctor
/// </summary> /// </summary>

View File

@ -21,6 +21,11 @@ namespace CryptoExchange.Net.Clients
{ {
#region fields #region fields
/// <summary>
/// Api clients in this client
/// </summary>
internal new List<SocketApiClient> ApiClients => base.ApiClients.OfType<SocketApiClient>().ToList();
/// <summary> /// <summary>
/// If client is disposing /// If client is disposing
/// </summary> /// </summary>
@ -135,6 +140,15 @@ namespace CryptoExchange.Net.Clients
return result; return result;
} }
/// <summary>
/// Update options
/// </summary>
public virtual void SetOptions(UpdateOptions options)
{
foreach (var apiClient in ApiClients)
apiClient.SetOptions(options);
}
} }
/// <inheritdoc /> /// <inheritdoc />
@ -147,6 +161,11 @@ namespace CryptoExchange.Net.Clients
/// </summary> /// </summary>
internal new List<SocketApiClient<TEnvironment, TApiCredentials>> ApiClients => base.ApiClients.OfType<SocketApiClient<TEnvironment, TApiCredentials>>().ToList(); internal new List<SocketApiClient<TEnvironment, TApiCredentials>> ApiClients => base.ApiClients.OfType<SocketApiClient<TEnvironment, TApiCredentials>>().ToList();
/// <summary>
/// Provided client options
/// </summary>
public new SocketExchangeOptions<TEnvironment, TApiCredentials> ClientOptions => (SocketExchangeOptions<TEnvironment, TApiCredentials>)base.ClientOptions;
/// <summary> /// <summary>
/// ctor /// ctor
/// </summary> /// </summary>

View File

@ -819,6 +819,16 @@ namespace CryptoExchange.Net.Clients
&& definition.Method == HttpMethod.Get && definition.Method == HttpMethod.Get
&& !definition.PreventCaching; && !definition.PreventCaching;
/// <inheritdoc />
public virtual void SetOptions(UpdateOptions options)
{
_proxyConfigured = options.Proxy != null;
ClientOptions.Proxy = options.Proxy;
ClientOptions.RequestTimeout = options.RequestTimeout ?? ClientOptions.RequestTimeout;
RequestFactory.UpdateSettings(options.Proxy, options.RequestTimeout ?? ClientOptions.RequestTimeout, ClientOptions.HttpKeepAliveInterval);
}
} }
/// <inheritdoc /> /// <inheritdoc />
@ -890,12 +900,9 @@ namespace CryptoExchange.Net.Clients
/// <inheritdoc /> /// <inheritdoc />
public virtual void SetOptions(UpdateOptions<TApiCredentials> options) public virtual void SetOptions(UpdateOptions<TApiCredentials> options)
{ {
_proxyConfigured = options.Proxy != null; base.SetOptions(options);
ClientOptions.Proxy = options.Proxy;
ClientOptions.RequestTimeout = options.RequestTimeout ?? ClientOptions.RequestTimeout;
ApiCredentials = (TApiCredentials?)options.ApiCredentials?.Copy() ?? ApiCredentials; ApiCredentials = (TApiCredentials?)options.ApiCredentials?.Copy() ?? ApiCredentials;
RequestFactory.UpdateSettings(options.Proxy, options.RequestTimeout ?? ClientOptions.RequestTimeout, ClientOptions.HttpKeepAliveInterval);
} }
} }

View File

@ -1035,6 +1035,28 @@ namespace CryptoExchange.Net.Clients
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public abstract ISocketMessageHandler CreateMessageConverter(WebSocketMessageType messageType); public abstract ISocketMessageHandler CreateMessageConverter(WebSocketMessageType messageType);
/// <inheritdoc />
public virtual void SetOptions(UpdateOptions options)
{
var previousProxyIsSet = _proxyConfigured;
ClientOptions.Proxy = options.Proxy;
ClientOptions.RequestTimeout = options.RequestTimeout ?? ClientOptions.RequestTimeout;
_proxyConfigured = options.Proxy != null;
if ((!previousProxyIsSet && options.Proxy == null)
|| _socketConnections.IsEmpty)
{
return;
}
_logger.LogInformation("Reconnecting websockets to apply proxy");
// Update proxy, also triggers reconnect
foreach (var connection in _socketConnections)
_ = connection.Value.UpdateProxy(options.Proxy);
}
} }
/// <inheritdoc /> /// <inheritdoc />
@ -1102,25 +1124,7 @@ namespace CryptoExchange.Net.Clients
/// <inheritdoc /> /// <inheritdoc />
public virtual void SetOptions(UpdateOptions<TApiCredentials> options) public virtual void SetOptions(UpdateOptions<TApiCredentials> options)
{ {
var previousProxyIsSet = _proxyConfigured; base.SetOptions(options);
ClientOptions.Proxy = options.Proxy;
ClientOptions.RequestTimeout = options.RequestTimeout ?? ClientOptions.RequestTimeout;
ApiCredentials = (TApiCredentials?)options.ApiCredentials?.Copy() ?? ApiCredentials;
_proxyConfigured = options.Proxy != null;
if ((!previousProxyIsSet && options.Proxy == null)
|| _socketConnections.IsEmpty)
{
return;
}
_logger.LogInformation("Reconnecting websockets to apply proxy");
// Update proxy, also triggers reconnect
foreach (var connection in _socketConnections)
_ = connection.Value.UpdateProxy(options.Proxy);
} }
} }

View File

@ -28,6 +28,12 @@ namespace CryptoExchange.Net.Interfaces.Clients
/// Whether client is disposed /// Whether client is disposed
/// </summary> /// </summary>
bool Disposed { get; } bool Disposed { get; }
/// <summary>
/// Update specific options
/// </summary>
/// <param name="options">Options to update. Only specific options are changeable after the client has been created</param>
void SetOptions(UpdateOptions options);
} }
/// <inheritdoc /> /// <inheritdoc />

View File

@ -60,6 +60,12 @@ namespace CryptoExchange.Net.Interfaces.Clients
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
Task UnsubscribeAllAsync(); Task UnsubscribeAllAsync();
/// <summary>
/// Update specific options
/// </summary>
/// <param name="options">Options to update. Only specific options are changeable after the client has been created</param>
void SetOptions(UpdateOptions options);
} }
/// <inheritdoc /> /// <inheritdoc />

View File

@ -6,19 +6,27 @@ namespace CryptoExchange.Net.Objects.Options
/// <summary> /// <summary>
/// Options to update /// Options to update
/// </summary> /// </summary>
public class UpdateOptions<TApiCredentials> where TApiCredentials : ApiCredentials public class UpdateOptions
{ {
/// <summary> /// <summary>
/// Proxy setting. Note that if this is not provided any previously set proxy will be reset /// Proxy setting. Note that if this is not provided any previously set proxy will be reset
/// </summary> /// </summary>
public ApiProxy? Proxy { get; set; } public ApiProxy? Proxy { get; set; }
/// <summary> /// <summary>
/// Api credentials
/// </summary>
public TApiCredentials? ApiCredentials { get; set; }
/// <summary>
/// Request timeout /// Request timeout
/// </summary> /// </summary>
public TimeSpan? RequestTimeout { get; set; } public TimeSpan? RequestTimeout { get; set; }
} }
/// <summary>
/// Options to update
/// </summary>
public class UpdateOptions<TApiCredentials>: UpdateOptions
where TApiCredentials : ApiCredentials
{
/// <summary>
/// Api credentials
/// </summary>
public TApiCredentials? ApiCredentials { get; set; }
}
} }