using CryptoExchange.Net.Authentication;
using CryptoExchange.Net.Interfaces.Clients;
using CryptoExchange.Net.Objects;
using CryptoExchange.Net.Objects.Options;
using CryptoExchange.Net.SharedApis;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Net.Http;
using System.Text;
namespace CryptoExchange.Net.Clients
{
///
public abstract class UserClientProvider
where TRestClient : IRestClient
where TRestOptions : RestExchangeOptions, new()
where TCredentials : ApiCredentials
where TEnvironment : TradeEnvironment
{
private ConcurrentDictionary _restClients = new ConcurrentDictionary();
private readonly IOptions _restOptions;
private readonly HttpClient _httpClient;
///
/// Logger factory
///
protected readonly ILoggerFactory? _loggerFactory;
///
public abstract string ExchangeName { get; }
///
/// ctor
///
public UserClientProvider(
HttpClient? httpClient,
ILoggerFactory? loggerFactory,
IOptions restOptions)
{
_httpClient = httpClient ?? new HttpClient();
_httpClient.Timeout = restOptions.Value.RequestTimeout;
_loggerFactory = loggerFactory;
_restOptions = restOptions;
}
private IOptions SetRestEnvironment(IOptions options, TEnvironment? environment)
{
if (environment == null)
return options;
var newRestClientOptions = new TRestOptions();
options.Value.Set(newRestClientOptions);
newRestClientOptions.Environment = environment;
return Options.Create(newRestClientOptions);
}
///
public virtual void InitializeUserClient(string userIdentifier, TCredentials credentials, TEnvironment? environment = null)
{
CreateRestClient(userIdentifier, credentials, environment);
}
///
public TRestClient GetRestClient(string userIdentifier, TCredentials? credentials = null, TEnvironment? environment = null)
{
if (!_restClients.TryGetValue(userIdentifier, out var client) || client.Disposed)
client = CreateRestClient(userIdentifier, credentials, environment);
return client;
}
private TRestClient CreateRestClient(string userIdentifier, TCredentials? credentials, TEnvironment? environment)
{
var clientRestOptions = SetRestEnvironment(_restOptions, environment);
var client = ConstructRestClient(_httpClient, _loggerFactory, clientRestOptions);
if (credentials != null)
{
_restClients[userIdentifier] = client;
client.SetApiCredentials(credentials);
}
return client;
}
///
/// Constructs a new instance of the rest client
///
protected abstract TRestClient ConstructRestClient(
HttpClient client,
ILoggerFactory? loggerFactory,
IOptions options);
///
public virtual void ClearUserClients(string userIdentifier)
{
_restClients.TryRemove(userIdentifier, out var restClient);
restClient?.Dispose();
}
///
public virtual void Clear()
{
foreach (var client in _restClients.Values)
client.Dispose();
_restClients.Clear();
}
///
/// Applies the provided options delegate to a new instance of the specified type.
///
protected static T ApplyOptionsDelegate(Action? del) where T : new()
{
var opts = new T();
del?.Invoke(opts);
return opts;
}
}
///
public abstract class UserClientProvider
: UserClientProvider
where TRestClient : IRestClient
where TSocketClient : ISocketClient
where TRestOptions : RestExchangeOptions, new()
where TSocketOptions : SocketExchangeOptions, new()
where TCredentials : ApiCredentials
where TEnvironment : TradeEnvironment
{
private ConcurrentDictionary _socketClients = new ConcurrentDictionary();
private readonly IOptions _socketOptions;
///
/// ctor
///
public UserClientProvider(
HttpClient? httpClient,
ILoggerFactory? loggerFactory,
IOptions restOptions,
IOptions socketOptions)
: base(httpClient, loggerFactory, restOptions)
{
_socketOptions = socketOptions;
}
private IOptions SetSocketEnvironment(IOptions options, TEnvironment? environment)
{
if (environment == null)
return options;
var newSocketClientOptions = new TSocketOptions();
options.Value.Set(newSocketClientOptions);
newSocketClientOptions.Environment = environment;
return Options.Create(newSocketClientOptions);
}
///
public override void InitializeUserClient(string userIdentifier, TCredentials credentials, TEnvironment? environment = null)
{
base.InitializeUserClient(userIdentifier, credentials, environment);
CreateSocketClient(userIdentifier, credentials, environment);
}
///
public TSocketClient GetSocketClient(string userIdentifier, TCredentials? credentials = null, TEnvironment? environment = null)
{
if (!_socketClients.TryGetValue(userIdentifier, out var client) || client.Disposed)
client = CreateSocketClient(userIdentifier, credentials, environment);
return client;
}
private TSocketClient CreateSocketClient(string userIdentifier, TCredentials? credentials, TEnvironment? environment)
{
var clientSocketOptions = SetSocketEnvironment(_socketOptions, environment);
var client = ConstructSocketClient(_loggerFactory, clientSocketOptions);
if (credentials != null)
{
_socketClients[userIdentifier] = client;
client.SetApiCredentials(credentials);
}
return client;
}
///
/// Constructs a new instance of the socket client
///
protected abstract TSocketClient ConstructSocketClient(
ILoggerFactory? loggerFactory,
IOptions options);
///
public override void ClearUserClients(string userIdentifier)
{
base.ClearUserClients(userIdentifier);
_socketClients.TryRemove(userIdentifier, out var socketClient);
socketClient?.Dispose();
}
///
public override void Clear()
{
base.Clear();
foreach (var client in _socketClients.Values)
client.Dispose();
_socketClients.Clear();
}
}
}