1
0
mirror of https://github.com/JKorf/CryptoExchange.Net synced 2026-04-13 00:22:22 +00:00
This commit is contained in:
Jkorf 2026-03-13 16:33:10 +01:00
parent c1068da227
commit 7598326bd5
22 changed files with 309 additions and 192 deletions

View File

@ -29,7 +29,7 @@ namespace CryptoExchange.Net.UnitTests
// act
// assert
Assert.Throws(typeof(ArgumentException),
() => new RestExchangeOptions<TestEnvironment>() { ApiCredentials = new ApiCredentials(key, secret) });
() => new RestExchangeOptions<TestEnvironment, TestCredentials>() { ApiCredentials = new TestCredentials(key, secret) });
}
[Test]
@ -38,13 +38,13 @@ namespace CryptoExchange.Net.UnitTests
// arrange, act
var options = new TestClientOptions
{
ApiCredentials = new ApiCredentials("123", "456"),
ApiCredentials = new TestCredentials("123", "456"),
ReceiveWindow = TimeSpan.FromSeconds(10)
};
// assert
Assert.That(options.ReceiveWindow == TimeSpan.FromSeconds(10));
Assert.That(options.ApiCredentials.GetCredential<HMACCredential>().Key == "123");
Assert.That(options.ApiCredentials.GetCredential<HMACCredential>().PublicKey == "123");
Assert.That(options.ApiCredentials.GetCredential<HMACCredential>().Secret == "456");
}
@ -53,13 +53,13 @@ namespace CryptoExchange.Net.UnitTests
{
// arrange, act
var options = new TestClientOptions();
options.Api1Options.ApiCredentials = new ApiCredentials("123", "456");
options.Api2Options.ApiCredentials = new ApiCredentials("789", "101");
options.Api1Options.ApiCredentials = new TestCredentials("123", "456");
options.Api2Options.ApiCredentials = new TestCredentials("789", "101");
// assert
Assert.That(options.Api1Options.ApiCredentials.GetCredential<HMACCredential>().Key == "123");
Assert.That(options.Api1Options.ApiCredentials.GetCredential<HMACCredential>().PublicKey == "123");
Assert.That(options.Api1Options.ApiCredentials.GetCredential<HMACCredential>().Secret == "456");
Assert.That(options.Api2Options.ApiCredentials.GetCredential<HMACCredential>().Key == "789");
Assert.That(options.Api2Options.ApiCredentials.GetCredential<HMACCredential>().PublicKey == "789");
Assert.That(options.Api2Options.ApiCredentials.GetCredential<HMACCredential>().Secret == "101");
}
@ -67,8 +67,8 @@ namespace CryptoExchange.Net.UnitTests
public void TestClientUsesCorrectOptions()
{
var client = new TestRestClient(options => {
options.Api1Options.ApiCredentials = new ApiCredentials("111", "222");
options.ApiCredentials = new ApiCredentials("333", "444");
options.Api1Options.ApiCredentials = new TestCredentials("111", "222");
options.ApiCredentials = new TestCredentials("333", "444");
});
var authProvider1 = (TestAuthProvider)client.Api1.AuthenticationProvider;
@ -82,8 +82,8 @@ namespace CryptoExchange.Net.UnitTests
[Test]
public void TestClientUsesCorrectOptionsWithDefault()
{
TestClientOptions.Default.ApiCredentials = new ApiCredentials("123", "456");
TestClientOptions.Default.Api1Options.ApiCredentials = new ApiCredentials("111", "222");
TestClientOptions.Default.ApiCredentials = new TestCredentials("123", "456");
TestClientOptions.Default.Api1Options.ApiCredentials = new TestCredentials("111", "222");
var client = new TestRestClient();
@ -102,17 +102,17 @@ namespace CryptoExchange.Net.UnitTests
[Test]
public void TestClientUsesCorrectOptionsWithOverridingDefault()
{
TestClientOptions.Default.ApiCredentials = new ApiCredentials("123", "456");
TestClientOptions.Default.Api1Options.ApiCredentials = new ApiCredentials("111", "222");
TestClientOptions.Default.ApiCredentials = new TestCredentials("123", "456");
TestClientOptions.Default.Api1Options.ApiCredentials = new TestCredentials("111", "222");
var client = new TestRestClient(options =>
{
options.Api1Options.ApiCredentials = new ApiCredentials("333", "444");
options.Api1Options.ApiCredentials = new TestCredentials("333", "444");
options.Environment = new TestEnvironment("Test", "https://test.test");
});
var authProvider1 = (TestAuthProvider)client.Api1.AuthenticationProvider;
var authProvider2 = (TestAuthProvider)client.Api2.AuthenticationProvider;
var authProvider1 = client.Api1.AuthenticationProvider;
var authProvider2 = client.Api2.AuthenticationProvider;
Assert.That(authProvider1.GetKey() == "333");
Assert.That(authProvider1.GetSecret() == "444");
Assert.That(authProvider2.GetKey() == "123");
@ -125,7 +125,7 @@ namespace CryptoExchange.Net.UnitTests
}
}
public class TestClientOptions: RestExchangeOptions<TestEnvironment>
public class TestClientOptions: RestExchangeOptions<TestEnvironment, TestCredentials>
{
/// <summary>
/// Default options for the futures client
@ -148,9 +148,9 @@ namespace CryptoExchange.Net.UnitTests
/// </summary>
public TimeSpan ReceiveWindow { get; set; } = TimeSpan.FromSeconds(5);
public RestApiOptions Api1Options { get; private set; } = new RestApiOptions();
public RestApiOptions<TestCredentials> Api1Options { get; private set; } = new RestApiOptions<TestCredentials>();
public RestApiOptions Api2Options { get; set; } = new RestApiOptions();
public RestApiOptions<TestCredentials> Api2Options { get; set; } = new RestApiOptions<TestCredentials>();
internal TestClientOptions Set(TestClientOptions targetOptions)
{

View File

@ -26,14 +26,14 @@ namespace CryptoExchange.Net.UnitTests
var options = new TestClientOptions();
_logger = NullLogger.Instance;
Initialize(options);
SubClient = AddApiClient(new TestSubClient(options, new RestApiOptions()));
SubClient = AddApiClient(new TestSubClient(options, new RestApiOptions<TestCredentials>()));
}
public TestBaseClient(TestClientOptions exchangeOptions) : base(null, "Test")
{
_logger = NullLogger.Instance;
Initialize(exchangeOptions);
SubClient = AddApiClient(new TestSubClient(exchangeOptions, new RestApiOptions()));
SubClient = AddApiClient(new TestSubClient(exchangeOptions, new RestApiOptions<TestCredentials>()));
}
public void Log(LogLevel verbosity, string data)
@ -42,11 +42,11 @@ namespace CryptoExchange.Net.UnitTests
}
}
public class TestSubClient : RestApiClient
public class TestSubClient : RestApiClient<TestEnvironment, TestAuthProvider, TestCredentials>
{
protected override IRestMessageHandler MessageHandler => throw new NotImplementedException();
public TestSubClient(RestExchangeOptions<TestEnvironment> options, RestApiOptions apiOptions) : base(new TraceLogger(), null, "https://localhost:123", options, apiOptions)
public TestSubClient(RestExchangeOptions<TestEnvironment, TestCredentials> options, RestApiOptions<TestCredentials> apiOptions) : base(new TraceLogger(), null, "https://localhost:123", options, apiOptions)
{
}
@ -58,24 +58,24 @@ namespace CryptoExchange.Net.UnitTests
/// <inheritdoc />
public override string FormatSymbol(string baseAsset, string quoteAsset, TradingMode futuresType, DateTime? deliverDate = null) => $"{baseAsset.ToUpperInvariant()}{quoteAsset.ToUpperInvariant()}";
protected override IMessageSerializer CreateSerializer() => new SystemTextJsonMessageSerializer(new System.Text.Json.JsonSerializerOptions());
protected override AuthenticationProvider CreateAuthenticationProvider(ApiCredentials credentials) => throw new NotImplementedException();
protected override TestAuthProvider CreateAuthenticationProvider(TestCredentials credentials) => throw new NotImplementedException();
protected override Task<WebCallResult<DateTime>> GetServerTimestampAsync() => throw new NotImplementedException();
}
public class TestAuthProvider : AuthenticationProvider
public class TestAuthProvider : AuthenticationProvider<TestCredentials, HMACCredential>
{
public override ApiCredentialsType[] SupportedCredentialTypes => [ApiCredentialsType.Hmac];
public TestAuthProvider(ApiCredentials credentials) : base(credentials)
public TestAuthProvider(TestCredentials credentials) : base(credentials)
{
}
public override void ProcessRequest(RestApiClient apiClient, RestRequestConfiguration requestConfig)
{
}
public string GetKey() => ((HMACCredential)Credential).Key;
public string GetSecret() => ((HMACCredential)Credential).Secret;
public string GetKey() => Credential.PublicKey;
public string GetSecret() => Credential.Secret;
}
public class TestEnvironment : TradeEnvironment
@ -87,4 +87,14 @@ namespace CryptoExchange.Net.UnitTests
TestAddress = url;
}
}
public class TestCredentials : ApiCredentials
{
public TestCredentials(string apiKey, string secret) : this(new HMACCredential(apiKey, secret)) { }
public TestCredentials(HMACCredential credential) : base(credential) { }
/// <inheritdoc />
public override ApiCredentials Copy() => new TestCredentials(Hmac!);
}
}

View File

@ -130,7 +130,7 @@ namespace CryptoExchange.Net.UnitTests.TestImplementations
}
}
public class TestRestApi1Client : RestApiClient
public class TestRestApi1Client : RestApiClient<TestEnvironment, TestAuthProvider, TestCredentials>
{
protected override IRestMessageHandler MessageHandler { get; } = new TestRestMessageHandler();
@ -159,7 +159,7 @@ namespace CryptoExchange.Net.UnitTests.TestImplementations
ParameterPositions[method] = position;
}
protected override AuthenticationProvider CreateAuthenticationProvider(ApiCredentials credentials)
protected override TestAuthProvider CreateAuthenticationProvider(TestCredentials credentials)
=> new TestAuthProvider(credentials);
protected override Task<WebCallResult<DateTime>> GetServerTimestampAsync()
@ -168,7 +168,7 @@ namespace CryptoExchange.Net.UnitTests.TestImplementations
}
}
public class TestRestApi2Client : RestApiClient
public class TestRestApi2Client : RestApiClient<TestEnvironment, TestAuthProvider, TestCredentials>
{
protected override IRestMessageHandler MessageHandler { get; } = new TestRestMessageHandler();
@ -186,8 +186,8 @@ namespace CryptoExchange.Net.UnitTests.TestImplementations
{
return await SendAsync<T>("http://www.test.com", new RequestDefinition("/", HttpMethod.Get) { Weight = 0 }, null, ct);
}
protected override AuthenticationProvider CreateAuthenticationProvider(ApiCredentials credentials)
protected override TestAuthProvider CreateAuthenticationProvider(TestCredentials credentials)
=> new TestAuthProvider(credentials);
protected override Task<WebCallResult<DateTime>> GetServerTimestampAsync()

View File

@ -16,6 +16,11 @@ namespace CryptoExchange.Net.Authentication
/// </summary>
public CredentialPair[] CredentialPairs { get; protected set; } = Array.Empty<CredentialPair>();
/// <summary>
/// The public key/identifier for the provided credentials
/// </summary>
public string PublicKey => CredentialPairs.First().PublicKey;
/// <summary>
/// HMAC credentials
/// </summary>
@ -25,6 +30,15 @@ namespace CryptoExchange.Net.Authentication
set => AddOrRemoveCredential(ApiCredentialsType.Hmac, value);
}
/// <summary>
/// RSA credentials in XML format
/// </summary>
public RSACredential? Rsa
{
get => (RSACredential?)CredentialPairs.SingleOrDefault(x => x.CredentialType == ApiCredentialsType.Rsa);
set => AddOrRemoveCredential(ApiCredentialsType.Rsa, value);
}
/// <summary>
/// RSA credentials in XML format
/// </summary>
@ -64,6 +78,15 @@ namespace CryptoExchange.Net.Authentication
set => AddOrRemoveCredential(ApiCredentialsType.Ecdsa, value);
}
/// <summary>
/// API key credentials
/// </summary>
public ApiKeyCredential? ApiKey
{
get => (ApiKeyCredential?)CredentialPairs.SingleOrDefault(x => x.CredentialType == ApiCredentialsType.ApiKey);
set => AddOrRemoveCredential(ApiCredentialsType.ApiKey, value);
}
/// <summary>
/// If credential is null attempt to remove the credential of the type, else add it
/// </summary>
@ -164,6 +187,7 @@ namespace CryptoExchange.Net.Authentication
/// <summary>
/// Load a key from a file
/// </summary>
#warning check
public static string ReadFromFile(string path)
{
using var fileStream = File.OpenRead(path);

View File

@ -22,6 +22,10 @@
/// </summary>
Ecdsa,
/// <summary>
/// API key credentials
/// </summary>
ApiKey,
/// <summary>
/// Custom / exchange specific
/// </summary>
Custom

View File

@ -27,7 +27,7 @@ namespace CryptoExchange.Net.Authentication
/// <summary>
/// The public identifier for the provided credentials
/// </summary>
public abstract string PublicIdentifier { get; }
public abstract string PublicKey { get; }
/// <summary>
/// The supported credential types
@ -233,18 +233,12 @@ namespace CryptoExchange.Net.Authentication
/// <summary>
/// HMACSHA256 sign the data and return the hash
/// </summary>
/// <param name="data">Data to sign</param>
/// <param name="outputType">String type</param>
/// <returns></returns>
protected string SignHMACSHA256(HMACCredential credential, string data, SignOutputType? outputType = null)
=> SignHMACSHA256(credential,Encoding.UTF8.GetBytes(data), outputType);
/// <summary>
/// HMACSHA256 sign the data and return the hash
/// </summary>
/// <param name="data">Data to sign</param>
/// <param name="outputType">String type</param>
/// <returns></returns>
protected string SignHMACSHA256(HMACCredential credential, byte[] data, SignOutputType? outputType = null)
{
using var encryptor = new HMACSHA256(credential.GetSBytes());
@ -255,18 +249,12 @@ namespace CryptoExchange.Net.Authentication
/// <summary>
/// HMACSHA384 sign the data and return the hash
/// </summary>
/// <param name="data">Data to sign</param>
/// <param name="outputType">String type</param>
/// <returns></returns>
protected string SignHMACSHA384(HMACCredential credential, string data, SignOutputType? outputType = null)
=> SignHMACSHA384(credential, Encoding.UTF8.GetBytes(data), outputType);
/// <summary>
/// HMACSHA384 sign the data and return the hash
/// </summary>
/// <param name="data">Data to sign</param>
/// <param name="outputType">String type</param>
/// <returns></returns>
protected string SignHMACSHA384(HMACCredential credential, byte[] data, SignOutputType? outputType = null)
{
using var encryptor = new HMACSHA384(credential.GetSBytes());
@ -277,18 +265,12 @@ namespace CryptoExchange.Net.Authentication
/// <summary>
/// HMACSHA512 sign the data and return the hash
/// </summary>
/// <param name="data">Data to sign</param>
/// <param name="outputType">String type</param>
/// <returns></returns>
protected string SignHMACSHA512(HMACCredential credential, string data, SignOutputType? outputType = null)
=> SignHMACSHA512(credential, Encoding.UTF8.GetBytes(data), outputType);
/// <summary>
/// HMACSHA512 sign the data and return the hash
/// </summary>
/// <param name="data">Data to sign</param>
/// <param name="outputType">String type</param>
/// <returns></returns>
protected string SignHMACSHA512(HMACCredential credential, byte[] data, SignOutputType? outputType = null)
{
using var encryptor = new HMACSHA512(credential.GetSBytes());
@ -299,9 +281,6 @@ namespace CryptoExchange.Net.Authentication
/// <summary>
/// SHA256 sign the data
/// </summary>
/// <param name="data"></param>
/// <param name="outputType"></param>
/// <returns></returns>
protected string SignRSASHA256(RSACredential credential, byte[] data, SignOutputType? outputType = null)
{
var rsa = credential.GetSigner();
@ -314,9 +293,6 @@ namespace CryptoExchange.Net.Authentication
/// <summary>
/// SHA384 sign the data
/// </summary>
/// <param name="data"></param>
/// <param name="outputType"></param>
/// <returns></returns>
protected string SignRSASHA384(RSACredential credential, byte[] data, SignOutputType? outputType = null)
{
var rsa = credential.GetSigner();
@ -329,9 +305,6 @@ namespace CryptoExchange.Net.Authentication
/// <summary>
/// SHA512 sign the data
/// </summary>
/// <param name="data"></param>
/// <param name="outputType"></param>
/// <returns></returns>
protected string SignRSASHA512(RSACredential credential, byte[] data, SignOutputType? outputType = null)
{
var rsa = credential.GetSigner();
@ -512,7 +485,7 @@ namespace CryptoExchange.Net.Authentication
public TCredentialType Credential { get; set; }
/// <inheritdoc />
public override string PublicIdentifier => Credential.PublicIdentifier;
public override string PublicKey => Credential.PublicKey;
/// <summary>
/// ctor

View File

@ -15,11 +15,38 @@ namespace CryptoExchange.Net.Authentication
/// <summary>
/// API credentials identifier
/// </summary>
public abstract string PublicIdentifier { get; }
public string PublicKey { get; set; }
/// <summary>
/// Type of credentials
/// </summary>
public abstract ApiCredentialsType CredentialType { get; }
/// <summary>
/// ctor
/// </summary>
public CredentialPair(string publicKey)
{
PublicKey = publicKey;
}
}
/// <summary>
/// Api key credentials
/// </summary>
public class ApiKeyCredential : CredentialPair
{
/// <inheritdoc />
public override ApiCredentialsType CredentialType => ApiCredentialsType.ApiKey;
/// <summary>
/// ctor
/// </summary>
/// <param name="key">Api key</param>
public ApiKeyCredential(string key) : base(key)
{
if (string.IsNullOrEmpty(key))
throw new ArgumentException("Key can't be null/empty");
}
}
/// <summary>
@ -29,10 +56,6 @@ namespace CryptoExchange.Net.Authentication
{
private byte[]? _sBytes;
/// <summary>
/// API key/label
/// </summary>
public string Key { get; set; }
/// <summary>
/// API secret
/// </summary>
@ -44,8 +67,6 @@ namespace CryptoExchange.Net.Authentication
/// <inheritdoc />
public override ApiCredentialsType CredentialType => ApiCredentialsType.Hmac;
/// <inheritdoc />
public override string PublicIdentifier => Key;
/// <summary>
/// ctor
@ -53,12 +74,11 @@ namespace CryptoExchange.Net.Authentication
/// <param name="key">Api key/label</param>
/// <param name="secret">Api secret</param>
/// <param name="pass">Optional passphrase</param>
public HMACCredential(string key, string secret, string? pass = null)
public HMACCredential(string key, string secret, string? pass = null) : base(key)
{
if (string.IsNullOrEmpty(key) || string.IsNullOrEmpty(secret))
throw new ArgumentException("Key and secret can't be null/empty");
Key = key;
Secret = secret;
Pass = pass;
}
@ -78,32 +98,31 @@ namespace CryptoExchange.Net.Authentication
/// </summary>
public abstract class RSACredential : CredentialPair
{
/// <summary>
/// Public key
/// </summary>
public string PublicKey { get; set; }
/// <summary>
/// Private key
/// </summary>
public string PrivateKey { get; set; }
/// <summary>
/// Passphrase
/// </summary>
public string? Passphrase { get; set; }
/// <inheritdoc />
public override ApiCredentialsType CredentialType => ApiCredentialsType.Rsa;
/// <inheritdoc />
public override string PublicIdentifier => PublicKey;
/// <summary>
/// ctor
/// </summary>
/// <param name="publicKey">Public key</param>
/// <param name="privateKey">Private key</param>
public RSACredential(string publicKey, string privateKey)
/// <param name="passphrase">Passphrase</param>
public RSACredential(string publicKey, string privateKey, string? passphrase = null) : base(publicKey)
{
if (string.IsNullOrEmpty(publicKey) || string.IsNullOrEmpty(privateKey))
throw new ArgumentException("Public and private key can't be null/empty");
PublicKey = publicKey;
PrivateKey = privateKey;
Passphrase = passphrase;
}
/// <summary>
@ -123,7 +142,8 @@ namespace CryptoExchange.Net.Authentication
/// </summary>
/// <param name="publicKey">Public key</param>
/// <param name="privateKey">Private key</param>
public RSAPemCredential(string publicKey, string privateKey): base(publicKey, privateKey)
/// <param name="passphrase">Passphrase</param>
public RSAPemCredential(string publicKey, string privateKey, string? passphrase = null) : base(publicKey, privateKey, passphrase)
{
}
@ -157,7 +177,8 @@ namespace CryptoExchange.Net.Authentication
/// </summary>
/// <param name="publicKey">Public key</param>
/// <param name="privateKey">Private key</param>
public RSAXmlCredential(string publicKey, string privateKey) : base(publicKey, privateKey)
/// <param name="passphrase">Passphrase</param>
public RSAXmlCredential(string publicKey, string privateKey, string? passphrase = null) : base(publicKey, privateKey, passphrase)
{
}
@ -180,29 +201,28 @@ namespace CryptoExchange.Net.Authentication
{
private Key? _signKey;
/// <summary>
/// Public key
/// </summary>
public string PublicKey { get; set; }
/// <summary>
/// Private key
/// </summary>
public string PrivateKey { get; set; }
/// <summary>
/// Passphrase
/// </summary>
public string? Passphrase { get; set; }
/// <inheritdoc />
public override ApiCredentialsType CredentialType => ApiCredentialsType.Ed25519;
/// <inheritdoc />
public override string PublicIdentifier => PublicKey;
/// <summary>
/// ctor
/// </summary>
/// <param name="publicKey">Public key</param>
/// <param name="privateKey">Private key</param>
public ED25519Credential(string publicKey, string privateKey)
/// <param name="passphrase">Passphrase</param>
public ED25519Credential(string publicKey, string privateKey, string? passphrase = null) : base(publicKey)
{
PublicKey = publicKey;
PrivateKey = privateKey;
Passphrase = passphrase;
}
/// <summary>
@ -230,29 +250,28 @@ namespace CryptoExchange.Net.Authentication
/// </summary>
public class ECDSACredential : CredentialPair
{
/// <summary>
/// Public key
/// </summary>
public string PublicKey { get; set; }
/// <summary>
/// Private key
/// </summary>
public string PrivateKey { get; set; }
/// <summary>
/// Passphrase
/// </summary>
public string? Passphrase { get; set; }
/// <inheritdoc />
public override ApiCredentialsType CredentialType => ApiCredentialsType.Ecdsa;
/// <inheritdoc />
public override string PublicIdentifier => PublicKey;
/// <summary>
/// ctor
/// </summary>
/// <param name="publicKey">Public key</param>
/// <param name="privateKey">Private key</param>
public ECDSACredential(string publicKey, string privateKey)
/// <param name="passphrase">Passphrase</param>
public ECDSACredential(string publicKey, string privateKey, string? passphrase = null) : base(publicKey)
{
PublicKey = publicKey;
PrivateKey = privateKey;
Passphrase = passphrase;
}
}
}

View File

@ -1,5 +1,4 @@
using System;
using CryptoExchange.Net.Authentication;
using CryptoExchange.Net.Interfaces.Clients;
using CryptoExchange.Net.Objects.Errors;
using CryptoExchange.Net.Objects.Options;
@ -74,7 +73,6 @@ namespace CryptoExchange.Net.Clients
/// <param name="logger">Logger</param>
/// <param name="outputOriginalData">Should data from this client include the original data in the call result</param>
/// <param name="baseAddress">Base address for this API client</param>
/// <param name="apiCredentials">Api credentials</param>
/// <param name="clientOptions">Client options</param>
/// <param name="apiOptions">Api options</param>
protected BaseApiClient(

View File

@ -31,6 +31,7 @@ namespace CryptoExchange.Net.Clients
}
/// <inheritdoc />
public abstract class BaseRestClient<TEnvironment, TApiCredentials> : BaseRestClient, IRestClient<TApiCredentials>
where TEnvironment : TradeEnvironment
where TApiCredentials : ApiCredentials

View File

@ -137,6 +137,7 @@ namespace CryptoExchange.Net.Clients
}
}
/// <inheritdoc />
public abstract class BaseSocketClient<TEnvironment, TApiCredentials> : BaseSocketClient, ISocketClient<TApiCredentials>
where TEnvironment : TradeEnvironment
where TApiCredentials : ApiCredentials
@ -159,7 +160,7 @@ namespace CryptoExchange.Net.Clients
/// Set the API credentials for this client. All Api clients in this client will use the new credentials, regardless of earlier set options.
/// </summary>
/// <param name="credentials">The credentials to set</param>
public void SetApiCredentials(TApiCredentials credentials)
public virtual void SetApiCredentials(TApiCredentials credentials)
{
foreach (var apiClient in ApiClients)
apiClient.SetApiCredentials(credentials);

View File

@ -104,7 +104,9 @@ namespace CryptoExchange.Net.Clients
/// </summary>
protected abstract IRestMessageHandler MessageHandler { get; }
/// <summary>
/// Get the AuthenticationProvider implementation, or null if no ApiCredentials are set
/// </summary>
public virtual AuthenticationProvider? GetAuthenticationProvider() => null;
/// <summary>
@ -332,7 +334,7 @@ namespace CryptoExchange.Net.Clients
RateLimitItemType.Request,
definition,
host,
GetAuthenticationProvider()?.PublicIdentifier,
GetAuthenticationProvider()?.PublicKey,
requestWeight,
ClientOptions.RateLimitingBehaviour,
rateLimitKeySuffix,
@ -358,7 +360,7 @@ namespace CryptoExchange.Net.Clients
RateLimitItemType.Request,
definition,
host,
GetAuthenticationProvider()?.PublicIdentifier,
GetAuthenticationProvider()?.PublicKey,
singleRequestWeight,
ClientOptions.RateLimitingBehaviour,
rateLimitKeySuffix,
@ -814,9 +816,13 @@ namespace CryptoExchange.Net.Clients
}
/// <inheritdoc />
public abstract class RestApiClient<TEnvironment> : RestApiClient, IRestApiClient
where TEnvironment : TradeEnvironment
{
/// <summary>
/// ctor
/// </summary>
protected RestApiClient(
ILogger logger,
HttpClient? httpClient,
@ -832,17 +838,71 @@ namespace CryptoExchange.Net.Clients
}
}
/// <inheritdoc />
public abstract class RestApiClient<TEnvironment, TApiCredentials> : RestApiClient<TEnvironment>, IRestApiClient<TApiCredentials>
where TApiCredentials : ApiCredentials
where TEnvironment : TradeEnvironment
{
/// <inheritdoc />
public TApiCredentials? ApiCredentials { get; set; }
/// <inheritdoc />
public bool Authenticated => ApiCredentials != null;
/// <inheritdoc />
public new RestExchangeOptions<TEnvironment, TApiCredentials> ClientOptions => (RestExchangeOptions<TEnvironment, TApiCredentials>)base.ClientOptions;
/// <inheritdoc />
public new RestApiOptions<TApiCredentials> ApiOptions => (RestApiOptions<TApiCredentials>)base.ApiOptions;
/// <summary>
/// ctor
/// </summary>
protected RestApiClient(
ILogger logger,
HttpClient? httpClient,
string baseAddress,
RestExchangeOptions<TEnvironment, TApiCredentials> options,
RestApiOptions<TApiCredentials> apiOptions) : base(
logger,
httpClient,
baseAddress,
options,
apiOptions)
{
ApiCredentials = apiOptions.ApiCredentials ?? options.ApiCredentials;
}
/// <inheritdoc />
public virtual void SetApiCredentials(TApiCredentials credentials)
{
ApiCredentials = (TApiCredentials)credentials.Copy();
}
/// <inheritdoc />
public virtual void SetOptions(UpdateOptions<TApiCredentials> options)
{
ClientOptions.Proxy = options.Proxy;
ClientOptions.RequestTimeout = options.RequestTimeout ?? ClientOptions.RequestTimeout;
ApiCredentials = (TApiCredentials?)options.ApiCredentials?.Copy() ?? ApiCredentials;
RequestFactory.UpdateSettings(options.Proxy, options.RequestTimeout ?? ClientOptions.RequestTimeout, ClientOptions.HttpKeepAliveInterval);
}
}
/// <inheritdoc />
public abstract class RestApiClient<TEnvironment, TAuthenticationProvider, TApiCredentials> : RestApiClient<TEnvironment, TApiCredentials>
where TApiCredentials : ApiCredentials
where TAuthenticationProvider : AuthenticationProvider<TApiCredentials>
where TEnvironment : TradeEnvironment
{
private bool _authProviderInitialized = false;
private AuthenticationProvider<TApiCredentials>? _authenticationProvider;
private TAuthenticationProvider? _authenticationProvider;
/// <summary>
/// The authentication provider for this API client. (null if no credentials are set)
/// </summary>
public AuthenticationProvider<TApiCredentials>? AuthenticationProvider
public TAuthenticationProvider? AuthenticationProvider
{
get
{
@ -859,21 +919,12 @@ namespace CryptoExchange.Net.Clients
internal set => _authenticationProvider = value;
}
/// <inheritdoc />
public TApiCredentials? ApiCredentials { get; set; }
/// <inheritdoc />
public bool Authenticated => ApiCredentials != null;
/// <inheritdoc />
public new RestExchangeOptions<TEnvironment, TApiCredentials> ClientOptions => (RestExchangeOptions<TEnvironment, TApiCredentials>)base.ClientOptions;
/// <inheritdoc />
public new RestApiOptions<TApiCredentials> ApiOptions => (RestApiOptions<TApiCredentials>)base.ApiOptions;
/// <inheritdoc />
public override AuthenticationProvider? GetAuthenticationProvider() => AuthenticationProvider;
/// <summary>
/// ctor
/// </summary>
protected RestApiClient(
ILogger logger,
HttpClient? httpClient,
@ -886,14 +937,6 @@ namespace CryptoExchange.Net.Clients
options,
apiOptions)
{
ApiCredentials = apiOptions.ApiCredentials ?? options.ApiCredentials;
}
/// <inheritdoc />
public void SetApiCredentials(TApiCredentials credentials)
{
ApiCredentials = (TApiCredentials)credentials.Copy();
AuthenticationProvider = CreateAuthenticationProvider(credentials);
}
/// <summary>
@ -901,19 +944,21 @@ namespace CryptoExchange.Net.Clients
/// </summary>
/// <param name="credentials"></param>
/// <returns></returns>
protected abstract AuthenticationProvider<TApiCredentials> CreateAuthenticationProvider(TApiCredentials credentials);
protected abstract TAuthenticationProvider CreateAuthenticationProvider(TApiCredentials credentials);
/// <inheritdoc />
public virtual void SetOptions(UpdateOptions<TApiCredentials> options)
public override void SetApiCredentials(TApiCredentials credentials)
{
ClientOptions.Proxy = options.Proxy;
ClientOptions.RequestTimeout = options.RequestTimeout ?? ClientOptions.RequestTimeout;
base.SetApiCredentials(credentials);
AuthenticationProvider = CreateAuthenticationProvider(credentials);
}
ApiCredentials = (TApiCredentials?)options.ApiCredentials?.Copy() ?? ApiCredentials;
/// <inheritdoc />
public override void SetOptions(UpdateOptions<TApiCredentials> options)
{
base.SetOptions(options);
if (ApiCredentials != null)
AuthenticationProvider = CreateAuthenticationProvider(ApiCredentials);
RequestFactory.UpdateSettings(options.Proxy, options.RequestTimeout ?? ClientOptions.RequestTimeout, ClientOptions.HttpKeepAliveInterval);
}
}
}

View File

@ -144,6 +144,9 @@ namespace CryptoExchange.Net.Clients
/// </summary>
public bool EnforceSequenceNumbers { get; set; }
/// <summary>
/// Get the AuthenticationProvider implementation, or null if no ApiCredentials are set
/// </summary>
public virtual AuthenticationProvider? GetAuthenticationProvider() => null;
#endregion
@ -1029,9 +1032,13 @@ namespace CryptoExchange.Net.Clients
public abstract ISocketMessageHandler CreateMessageConverter(WebSocketMessageType messageType);
}
/// <inheritdoc />
public abstract class SocketApiClient<TEnvironment> : SocketApiClient, ISocketApiClient
where TEnvironment : TradeEnvironment
{
/// <summary>
/// ctor
/// </summary>
protected SocketApiClient(
ILogger logger,
string baseAddress,
@ -1045,17 +1052,82 @@ namespace CryptoExchange.Net.Clients
}
}
/// <inheritdoc />
public abstract class SocketApiClient<TEnvironment, TApiCredentials> : SocketApiClient<TEnvironment>, ISocketApiClient<TApiCredentials>
where TApiCredentials : ApiCredentials
where TEnvironment : TradeEnvironment
{
/// <inheritdoc />
public TApiCredentials? ApiCredentials { get; set; }
/// <inheritdoc />
public bool Authenticated => ApiCredentials != null;
/// <inheritdoc />
public new SocketExchangeOptions<TEnvironment, TApiCredentials> ClientOptions => (SocketExchangeOptions<TEnvironment, TApiCredentials>)base.ClientOptions;
/// <inheritdoc />
public new SocketApiOptions<TApiCredentials> ApiOptions => (SocketApiOptions<TApiCredentials>)base.ApiOptions;
/// <summary>
/// ctor
/// </summary>
protected SocketApiClient(
ILogger logger,
string baseAddress,
SocketExchangeOptions<TEnvironment, TApiCredentials> options,
SocketApiOptions<TApiCredentials> apiOptions) : base(
logger,
baseAddress,
options,
apiOptions)
{
ApiCredentials = apiOptions.ApiCredentials ?? options.ApiCredentials;
}
/// <inheritdoc />
public virtual void SetApiCredentials(TApiCredentials credentials)
{
ApiCredentials = (TApiCredentials)credentials.Copy();
}
/// <inheritdoc />
public virtual void SetOptions(UpdateOptions<TApiCredentials> options)
{
var previousProxyIsSet = ClientOptions.Proxy != null;
ClientOptions.Proxy = options.Proxy;
ClientOptions.RequestTimeout = options.RequestTimeout ?? ClientOptions.RequestTimeout;
ApiCredentials = (TApiCredentials?)options.ApiCredentials?.Copy() ?? ApiCredentials;
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 />
public abstract class SocketApiClient<TEnvironment, TAuthenticationProvider, TApiCredentials> : SocketApiClient<TEnvironment, TApiCredentials>
where TAuthenticationProvider : AuthenticationProvider<TApiCredentials>
where TApiCredentials : ApiCredentials
where TEnvironment : TradeEnvironment
{
private bool _authProviderInitialized = false;
private AuthenticationProvider<TApiCredentials>? _authenticationProvider;
private TAuthenticationProvider? _authenticationProvider;
/// <summary>
/// The authentication provider for this API client. (null if no credentials are set)
/// </summary>
public AuthenticationProvider<TApiCredentials>? AuthenticationProvider
public TAuthenticationProvider? AuthenticationProvider
{
get
{
@ -1072,21 +1144,12 @@ namespace CryptoExchange.Net.Clients
internal set => _authenticationProvider = value;
}
/// <inheritdoc />
public TApiCredentials? ApiCredentials { get; set; }
/// <inheritdoc />
public bool Authenticated => ApiCredentials != null;
/// <inheritdoc />
public new SocketExchangeOptions<TEnvironment, TApiCredentials> ClientOptions => (SocketExchangeOptions<TEnvironment, TApiCredentials>)base.ClientOptions;
/// <inheritdoc />
public new SocketApiOptions<TApiCredentials> ApiOptions => (SocketApiOptions<TApiCredentials>)base.ApiOptions;
/// <inheritdoc />
public override AuthenticationProvider? GetAuthenticationProvider() => AuthenticationProvider;
/// <summary>
/// ctor
/// </summary>
protected SocketApiClient(
ILogger logger,
string baseAddress,
@ -1097,7 +1160,6 @@ namespace CryptoExchange.Net.Clients
options,
apiOptions)
{
ApiCredentials = apiOptions.ApiCredentials ?? options.ApiCredentials;
}
/// <summary>
@ -1105,38 +1167,21 @@ namespace CryptoExchange.Net.Clients
/// </summary>
/// <param name="credentials"></param>
/// <returns></returns>
protected abstract AuthenticationProvider<TApiCredentials> CreateAuthenticationProvider(TApiCredentials credentials);
protected abstract TAuthenticationProvider CreateAuthenticationProvider(TApiCredentials credentials);
/// <inheritdoc />
public void SetApiCredentials(TApiCredentials credentials)
public override void SetApiCredentials(TApiCredentials credentials)
{
ApiCredentials = (TApiCredentials)credentials.Copy();
AuthenticationProvider = CreateAuthenticationProvider(ApiCredentials);
AuthenticationProvider = CreateAuthenticationProvider(credentials);
base.SetApiCredentials(credentials);
}
/// <inheritdoc />
public virtual void SetOptions(UpdateOptions<TApiCredentials> options)
public override void SetOptions(UpdateOptions<TApiCredentials> options)
{
var previousProxyIsSet = ClientOptions.Proxy != null;
ClientOptions.Proxy = options.Proxy;
ClientOptions.RequestTimeout = options.RequestTimeout ?? ClientOptions.RequestTimeout;
ApiCredentials = (TApiCredentials?)options.ApiCredentials?.Copy() ?? ApiCredentials;
if (ApiCredentials != null)
AuthenticationProvider = CreateAuthenticationProvider(ApiCredentials);
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);
base.SetOptions(options);
}
}
}

View File

@ -19,6 +19,7 @@ namespace CryptoExchange.Net.Interfaces.Clients
int TotalRequestsMade { get; set; }
}
/// <inheritdoc />
public interface IRestApiClient<TApiCredentials> : IRestApiClient
where TApiCredentials : ApiCredentials
{

View File

@ -30,6 +30,7 @@ namespace CryptoExchange.Net.Interfaces.Clients
bool Disposed { get; }
}
/// <inheritdoc />
public interface IRestClient<TApiCredentials> : IRestClient where TApiCredentials : ApiCredentials
{
/// <summary>
@ -38,10 +39,10 @@ namespace CryptoExchange.Net.Interfaces.Clients
/// <param name="credentials">The credentials to set</param>
void SetApiCredentials(TApiCredentials credentials);
///// <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<TApiCredentials> options);
/// <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<TApiCredentials> options);
}
}

View File

@ -75,6 +75,7 @@ namespace CryptoExchange.Net.Interfaces.Clients
Task<CallResult> PrepareConnectionsAsync();
}
/// <inheritdoc />
public interface ISocketApiClient<TApiCredentials> : ISocketApiClient
where TApiCredentials : ApiCredentials
{

View File

@ -62,6 +62,7 @@ namespace CryptoExchange.Net.Interfaces.Clients
Task UnsubscribeAllAsync();
}
/// <inheritdoc />
public interface ISocketClient<TApiCredentials> : ISocketClient where TApiCredentials : ApiCredentials
{

View File

@ -1,6 +1,4 @@
using CryptoExchange.Net.Authentication;
namespace CryptoExchange.Net.Objects.Options
namespace CryptoExchange.Net.Objects.Options
{
/// <summary>
/// Options for API usage

View File

@ -43,10 +43,4 @@ namespace CryptoExchange.Net.Objects.Options
return $"RequestTimeout: {RequestTimeout}, Proxy: {(Proxy == null ? "-" : "set")}";
}
}
public class ExchangeOptions<TApiCredentials> : ExchangeOptions
where TApiCredentials : ApiCredentials
{
}
}

View File

@ -25,6 +25,7 @@ namespace CryptoExchange.Net.Objects.Options
}
}
/// <inheritdoc />
public class RestApiOptions<TApiCredentials> : RestApiOptions where TApiCredentials : ApiCredentials
{
/// <summary>
@ -35,7 +36,7 @@ namespace CryptoExchange.Net.Objects.Options
/// <summary>
/// Set the values of this options on the target options
/// </summary>
public T Set<T>(T item) where T : RestApiOptions<TApiCredentials>, new()
public new T Set<T>(T item) where T : RestApiOptions<TApiCredentials>, new()
{
base.Set(item);
item.ApiCredentials = (TApiCredentials?)ApiCredentials?.Copy();

View File

@ -65,7 +65,6 @@ namespace CryptoExchange.Net.Objects.Options
item.OutputOriginalData = OutputOriginalData;
item.AutoTimestamp = AutoTimestamp;
item.TimestampRecalculationInterval = TimestampRecalculationInterval;
//item.ApiCredentials = (TApiCredentials?)ApiCredentials?.Copy();
item.Proxy = Proxy;
item.RequestTimeout = RequestTimeout;
item.RateLimiterEnabled = RateLimiterEnabled;
@ -84,6 +83,7 @@ namespace CryptoExchange.Net.Objects.Options
}
}
/// <inheritdoc />
public class RestExchangeOptions<TEnvironment> : RestExchangeOptions
where TEnvironment : TradeEnvironment
{
@ -98,7 +98,7 @@ namespace CryptoExchange.Net.Objects.Options
/// <summary>
/// Set the values of this options on the target options
/// </summary>
public T Set<T>(T target) where T : RestExchangeOptions<TEnvironment>, new()
public new T Set<T>(T target) where T : RestExchangeOptions<TEnvironment>, new()
{
base.Set(target);
target.Environment = Environment;
@ -106,9 +106,7 @@ namespace CryptoExchange.Net.Objects.Options
}
}
/// <summary>
/// Options for a rest exchange client
/// </summary>
/// <inheritdoc />
public class RestExchangeOptions<TEnvironment, TApiCredentials> : RestExchangeOptions<TEnvironment>
where TEnvironment : TradeEnvironment
where TApiCredentials : ApiCredentials

View File

@ -32,6 +32,7 @@ namespace CryptoExchange.Net.Objects.Options
}
}
/// <inheritdoc />
public class SocketApiOptions<TApiCredentials> : SocketApiOptions where TApiCredentials : ApiCredentials
{
/// <summary>
@ -42,7 +43,7 @@ namespace CryptoExchange.Net.Objects.Options
/// <summary>
/// Set the values of this options on the target options
/// </summary>
public T Set<T>(T item) where T : SocketApiOptions<TApiCredentials>, new()
public new T Set<T>(T item) where T : SocketApiOptions<TApiCredentials>, new()
{
base.Set(item);
item.ApiCredentials = (TApiCredentials?)ApiCredentials?.Copy();

View File

@ -110,6 +110,7 @@ namespace CryptoExchange.Net.Objects.Options
}
}
/// <inheritdoc />
public class SocketExchangeOptions<TEnvironment> : SocketExchangeOptions
where TEnvironment : TradeEnvironment
{