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(); } } }