mirror of
https://github.com/JKorf/CryptoExchange.Net
synced 2025-06-07 16:06:15 +00:00
Feature/update settings (#225)
Added SetOptions method to update client settings Added SocketConnection parameter to PeriodicQuery callback Added setting of DefaultProxyCredentials on HttpClient instance when client is not provided by DI Added support for overriding request time out per request Changed max wait time for close handshake response from 5 seconds to 1 second Fixed exception in trade tracker when there is no data in the initial snapshot
This commit is contained in:
parent
8605196390
commit
0be1bb16e3
@ -93,6 +93,17 @@ namespace CryptoExchange.Net.Clients
|
|||||||
AuthenticationProvider = CreateAuthenticationProvider(credentials.Copy());
|
AuthenticationProvider = CreateAuthenticationProvider(credentials.Copy());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public virtual void SetOptions<T>(UpdateOptions<T> options) where T : ApiCredentials
|
||||||
|
{
|
||||||
|
ClientOptions.Proxy = options.Proxy;
|
||||||
|
ClientOptions.RequestTimeout = options.RequestTimeout ?? ClientOptions.RequestTimeout;
|
||||||
|
|
||||||
|
ApiOptions.ApiCredentials = options.ApiCredentials ?? ClientOptions.ApiCredentials;
|
||||||
|
if (options.ApiCredentials != null)
|
||||||
|
AuthenticationProvider = CreateAuthenticationProvider(options.ApiCredentials.Copy());
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Dispose
|
/// Dispose
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -961,6 +961,14 @@ namespace CryptoExchange.Net.Clients
|
|||||||
/// <returns>Server time</returns>
|
/// <returns>Server time</returns>
|
||||||
protected virtual Task<WebCallResult<DateTime>> GetServerTimestampAsync() => throw new NotImplementedException();
|
protected virtual Task<WebCallResult<DateTime>> GetServerTimestampAsync() => throw new NotImplementedException();
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void SetOptions<T>(UpdateOptions<T> options)
|
||||||
|
{
|
||||||
|
base.SetOptions(options);
|
||||||
|
|
||||||
|
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();
|
||||||
|
@ -158,7 +158,7 @@ namespace CryptoExchange.Net.Clients
|
|||||||
/// <param name="interval"></param>
|
/// <param name="interval"></param>
|
||||||
/// <param name="queryDelegate"></param>
|
/// <param name="queryDelegate"></param>
|
||||||
/// <param name="callback"></param>
|
/// <param name="callback"></param>
|
||||||
protected virtual void RegisterPeriodicQuery(string identifier, TimeSpan interval, Func<SocketConnection, Query> queryDelegate, Action<CallResult>? callback)
|
protected virtual void RegisterPeriodicQuery(string identifier, TimeSpan interval, Func<SocketConnection, Query> queryDelegate, Action<SocketConnection, CallResult>? callback)
|
||||||
{
|
{
|
||||||
PeriodicTaskRegistrations.Add(new PeriodicTaskRegistration
|
PeriodicTaskRegistrations.Add(new PeriodicTaskRegistration
|
||||||
{
|
{
|
||||||
@ -422,9 +422,10 @@ namespace CryptoExchange.Net.Clients
|
|||||||
result.Error!.Message = "Authentication failed: " + result.Error.Message;
|
result.Error!.Message = "Authentication failed: " + result.Error.Message;
|
||||||
return new CallResult(result.Error)!;
|
return new CallResult(result.Error)!;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_logger.Authenticated(socket.SocketId);
|
||||||
}
|
}
|
||||||
|
|
||||||
_logger.Authenticated(socket.SocketId);
|
|
||||||
socket.Authenticated = true;
|
socket.Authenticated = true;
|
||||||
return new CallResult(null);
|
return new CallResult(null);
|
||||||
}
|
}
|
||||||
@ -710,6 +711,25 @@ namespace CryptoExchange.Net.Clients
|
|||||||
return new CallResult(null);
|
return new CallResult(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void SetOptions<T>(UpdateOptions<T> options)
|
||||||
|
{
|
||||||
|
var previousProxyIsSet = ClientOptions.Proxy != null;
|
||||||
|
base.SetOptions(options);
|
||||||
|
|
||||||
|
if ((!previousProxyIsSet && options.Proxy == null)
|
||||||
|
|| !socketConnections.Any())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.LogInformation("Reconnecting websockets to apply proxy");
|
||||||
|
|
||||||
|
// Update proxy, also triggers reconnect
|
||||||
|
foreach (var connection in socketConnections)
|
||||||
|
_ = connection.Value.UpdateProxy(options.Proxy);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Log the current state of connections and subscriptions
|
/// Log the current state of connections and subscriptions
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using CryptoExchange.Net.Authentication;
|
using CryptoExchange.Net.Authentication;
|
||||||
using CryptoExchange.Net.Objects;
|
using CryptoExchange.Net.Objects;
|
||||||
|
using CryptoExchange.Net.Objects.Options;
|
||||||
using CryptoExchange.Net.SharedApis;
|
using CryptoExchange.Net.SharedApis;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
@ -31,5 +32,12 @@ namespace CryptoExchange.Net.Interfaces
|
|||||||
/// <typeparam name="T"></typeparam>
|
/// <typeparam name="T"></typeparam>
|
||||||
/// <param name="credentials"></param>
|
/// <param name="credentials"></param>
|
||||||
void SetApiCredentials<T>(T credentials) where T : ApiCredentials;
|
void SetApiCredentials<T>(T credentials) where T : ApiCredentials;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Set new options. Note that when using a proxy this should be provided in the options even when already set before or it will be reset.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">Api crentials type</typeparam>
|
||||||
|
/// <param name="options">Options to set</param>
|
||||||
|
void SetOptions<T>(UpdateOptions<T> options) where T : ApiCredentials;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -24,6 +24,13 @@ namespace CryptoExchange.Net.Interfaces
|
|||||||
/// <param name="requestTimeout">Request timeout to use</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>
|
||||||
/// <param name="proxy">Optional proxy to use when no http client is provided</param>
|
/// <param name="proxy">Optional proxy to use when no http client is provided</param>
|
||||||
void Configure(ApiProxy? proxy, TimeSpan requestTimeout, HttpClient? httpClient=null);
|
void Configure(ApiProxy? proxy, TimeSpan requestTimeout, HttpClient? httpClient = null);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Update settings
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="proxy">Proxy to use</param>
|
||||||
|
/// <param name="requestTimeout">Request timeout to use</param>
|
||||||
|
void UpdateSettings(ApiProxy? proxy, TimeSpan requestTimeout);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -93,5 +93,10 @@ namespace CryptoExchange.Net.Interfaces
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task CloseAsync();
|
Task CloseAsync();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Update proxy setting
|
||||||
|
/// </summary>
|
||||||
|
void UpdateProxy(ApiProxy? proxy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
29
CryptoExchange.Net/Objects/Options/UpdateOptions.cs
Normal file
29
CryptoExchange.Net/Objects/Options/UpdateOptions.cs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
using CryptoExchange.Net.Authentication;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace CryptoExchange.Net.Objects.Options
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Options to update
|
||||||
|
/// </summary>
|
||||||
|
public class UpdateOptions<T> where T : ApiCredentials
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Proxy setting. Note that if this is not provided any previously set proxy will be reset
|
||||||
|
/// </summary>
|
||||||
|
public ApiProxy? Proxy { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Api credentials
|
||||||
|
/// </summary>
|
||||||
|
public T? ApiCredentials { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Request timeout
|
||||||
|
/// </summary>
|
||||||
|
public TimeSpan? RequestTimeout { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public class UpdateOptions : UpdateOptions<ApiCredentials> { }
|
||||||
|
}
|
@ -17,28 +17,7 @@ namespace CryptoExchange.Net.Requests
|
|||||||
public void Configure(ApiProxy? proxy, TimeSpan requestTimeout, HttpClient? client = null)
|
public void Configure(ApiProxy? proxy, TimeSpan requestTimeout, HttpClient? client = null)
|
||||||
{
|
{
|
||||||
if (client == null)
|
if (client == null)
|
||||||
{
|
client = CreateClient(proxy, requestTimeout);
|
||||||
var handler = new HttpClientHandler();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
handler.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
|
|
||||||
}
|
|
||||||
catch (PlatformNotSupportedException) { }
|
|
||||||
|
|
||||||
if (proxy != null)
|
|
||||||
{
|
|
||||||
handler.Proxy = new WebProxy
|
|
||||||
{
|
|
||||||
Address = new Uri($"{proxy.Host}:{proxy.Port}"),
|
|
||||||
Credentials = proxy.Password == null ? null : new NetworkCredential(proxy.Login, proxy.Password)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
client = new HttpClient(handler)
|
|
||||||
{
|
|
||||||
Timeout = requestTimeout
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
_httpClient = client;
|
_httpClient = client;
|
||||||
}
|
}
|
||||||
@ -51,5 +30,37 @@ namespace CryptoExchange.Net.Requests
|
|||||||
|
|
||||||
return new Request(new HttpRequestMessage(method, uri), _httpClient, requestId);
|
return new Request(new HttpRequestMessage(method, uri), _httpClient, requestId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void UpdateSettings(ApiProxy? proxy, TimeSpan requestTimeout)
|
||||||
|
{
|
||||||
|
_httpClient = CreateClient(proxy, requestTimeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
private HttpClient CreateClient(ApiProxy? proxy, TimeSpan requestTimeout)
|
||||||
|
{
|
||||||
|
var handler = new HttpClientHandler();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
handler.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
|
||||||
|
handler.DefaultProxyCredentials = CredentialCache.DefaultCredentials;
|
||||||
|
}
|
||||||
|
catch (PlatformNotSupportedException) { }
|
||||||
|
|
||||||
|
if (proxy != null)
|
||||||
|
{
|
||||||
|
handler.Proxy = new WebProxy
|
||||||
|
{
|
||||||
|
Address = new Uri($"{proxy.Host}:{proxy.Port}"),
|
||||||
|
Credentials = proxy.Password == null ? null : new NetworkCredential(proxy.Login, proxy.Password)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
var client = new HttpClient(handler)
|
||||||
|
{
|
||||||
|
Timeout = requestTimeout
|
||||||
|
};
|
||||||
|
return client;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -155,6 +155,12 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
_baseAddress = $"{Uri.Scheme}://{Uri.Host}";
|
_baseAddress = $"{Uri.Scheme}://{Uri.Host}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void UpdateProxy(ApiProxy? proxy)
|
||||||
|
{
|
||||||
|
Parameters.Proxy = proxy;
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public virtual async Task<CallResult> ConnectAsync()
|
public virtual async Task<CallResult> ConnectAsync()
|
||||||
{
|
{
|
||||||
@ -435,8 +441,8 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
{
|
{
|
||||||
// Wait until we receive close confirmation
|
// Wait until we receive close confirmation
|
||||||
await Task.Delay(10).ConfigureAwait(false);
|
await Task.Delay(10).ConfigureAwait(false);
|
||||||
if (DateTime.UtcNow - startWait > TimeSpan.FromSeconds(5))
|
if (DateTime.UtcNow - startWait > TimeSpan.FromSeconds(1))
|
||||||
break; // Wait for max 5 seconds, then just abort the connection
|
break; // Wait for max 1 second, then just abort the connection
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,6 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Callback after query
|
/// Callback after query
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Action<CallResult>? Callback { get; set; }
|
public Action<SocketConnection, CallResult>? Callback { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,11 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool Completed { get; set; }
|
public bool Completed { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Timeout for the request
|
||||||
|
/// </summary>
|
||||||
|
public TimeSpan? RequestTimeout { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The number of required responses. Can be more than 1 when for example subscribing multiple symbols streams in a single request,
|
/// The number of required responses. Can be more than 1 when for example subscribing multiple symbols streams in a single request,
|
||||||
/// and each symbol receives it's own confirmation response
|
/// and each symbol receives it's own confirmation response
|
||||||
|
@ -11,6 +11,8 @@ using System.Diagnostics;
|
|||||||
using CryptoExchange.Net.Clients;
|
using CryptoExchange.Net.Clients;
|
||||||
using CryptoExchange.Net.Logging.Extensions;
|
using CryptoExchange.Net.Logging.Extensions;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
using CryptoExchange.Net.Objects.Options;
|
||||||
|
using CryptoExchange.Net.Authentication;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Sockets
|
namespace CryptoExchange.Net.Sockets
|
||||||
{
|
{
|
||||||
@ -437,7 +439,7 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
query.IsSend(ApiClient.ClientOptions.RequestTimeout);
|
query.IsSend(query.RequestTimeout ?? ApiClient.ClientOptions.RequestTimeout);
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -583,6 +585,16 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task TriggerReconnectAsync() => await _socket.ReconnectAsync().ConfigureAwait(false);
|
public async Task TriggerReconnectAsync() => await _socket.ReconnectAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Update the proxy setting and reconnect
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="proxy">New proxy setting</param>
|
||||||
|
public async Task UpdateProxy(ApiProxy? proxy)
|
||||||
|
{
|
||||||
|
_socket.UpdateProxy(proxy);
|
||||||
|
await TriggerReconnectAsync().ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Close the connection
|
/// Close the connection
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -988,7 +1000,7 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
/// <param name="interval">How often</param>
|
/// <param name="interval">How often</param>
|
||||||
/// <param name="queryDelegate">Method returning the query to send</param>
|
/// <param name="queryDelegate">Method returning the query to send</param>
|
||||||
/// <param name="callback">The callback for processing the response</param>
|
/// <param name="callback">The callback for processing the response</param>
|
||||||
public virtual void QueryPeriodic(string identifier, TimeSpan interval, Func<SocketConnection, Query> queryDelegate, Action<CallResult>? callback)
|
public virtual void QueryPeriodic(string identifier, TimeSpan interval, Func<SocketConnection, Query> queryDelegate, Action<SocketConnection, CallResult>? callback)
|
||||||
{
|
{
|
||||||
if (queryDelegate == null)
|
if (queryDelegate == null)
|
||||||
throw new ArgumentNullException(nameof(queryDelegate));
|
throw new ArgumentNullException(nameof(queryDelegate));
|
||||||
@ -1020,7 +1032,7 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var result = await SendAndWaitQueryAsync(query).ConfigureAwait(false);
|
var result = await SendAndWaitQueryAsync(query).ConfigureAwait(false);
|
||||||
callback?.Invoke(result);
|
callback?.Invoke(this, result);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
@ -25,5 +25,7 @@ namespace CryptoExchange.Net.Testing.Implementations
|
|||||||
_request.RequestId = requestId;
|
_request.RequestId = requestId;
|
||||||
return _request;
|
return _request;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void UpdateSettings(ApiProxy? proxy, TimeSpan requestTimeout) {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -92,5 +92,7 @@ namespace CryptoExchange.Net.Testing.Implementations
|
|||||||
|
|
||||||
public Task ReconnectAsync() => throw new NotImplementedException();
|
public Task ReconnectAsync() => throw new NotImplementedException();
|
||||||
public void Dispose() { }
|
public void Dispose() { }
|
||||||
|
|
||||||
|
public void UpdateProxy(ApiProxy? proxy) => throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -350,7 +350,8 @@ namespace CryptoExchange.Net.Trackers.Trades
|
|||||||
_data.Add(item);
|
_data.Add(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
_firstTimestamp = _data.Min(v => v.Timestamp);
|
if (_data.Any())
|
||||||
|
_firstTimestamp = _data.Min(v => v.Timestamp);
|
||||||
|
|
||||||
ApplyWindow(false);
|
ApplyWindow(false);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user