using CryptoExchange.Net.Authentication; using CryptoExchange.Net.Objects.Options; using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; using System.Threading; namespace CryptoExchange.Net.Clients { /// /// The base for all clients, websocket client and rest client /// public abstract class BaseClient : IDisposable { /// /// Version of the CryptoExchange.Net base library /// public Version CryptoExchangeLibVersion { get; } = typeof(BaseClient).Assembly.GetName().Version!; /// /// Version of the client implementation /// public Version ExchangeLibVersion { get { lock(_versionLock) { if (_exchangeVersion == null) _exchangeVersion = GetType().Assembly.GetName().Version!; return _exchangeVersion; } } } /// /// The name of the API the client is for /// public string Exchange { get; } /// /// Whether client is disposed /// public bool Disposed { get; private set; } /// /// Api clients in this client /// internal List ApiClients { get; } = new List(); /// /// The log object /// protected internal ILogger _logger; #if NET9_0_OR_GREATER private readonly Lock _versionLock = new Lock(); #else private readonly object _versionLock = new object(); #endif private Version _exchangeVersion; /// /// Provided client options /// public ExchangeOptions ClientOptions { get; private set; } /// /// ctor /// /// Logger /// The name of the exchange this client is for #pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. protected BaseClient(ILoggerFactory? logger, string exchange) #pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. { Exchange = exchange; } /// /// Initialize the client with the specified options /// /// /// protected virtual void Initialize(ExchangeOptions options) { if (options == null) throw new ArgumentNullException(nameof(options)); ClientOptions = options; _logger.Log(LogLevel.Trace, $"Client configuration: {options}, CryptoExchange.Net: v{CryptoExchangeLibVersion}, {Exchange}.Net: v{ExchangeLibVersion}"); } /// /// Set the API credentials for this client. All Api clients in this client will use the new credentials, regardless of earlier set options. /// /// The credentials to set protected virtual void SetApiCredentials(T credentials) where T : ApiCredentials { foreach (var apiClient in ApiClients) apiClient.SetApiCredentials(credentials); } /// /// Register an API client /// /// The client protected T AddApiClient(T apiClient) where T : BaseApiClient { if (ClientOptions == null) throw new InvalidOperationException("Client should have called Initialize before adding API clients"); ApiClients.Add(apiClient); return apiClient; } /// /// Apply the options delegate to a new options instance /// protected static T ApplyOptionsDelegate(Action? del) where T: new() { var opts = new T(); del?.Invoke(opts); return opts; } /// /// Dispose /// public virtual void Dispose() { Disposed = true; foreach (var client in ApiClients) client.Dispose(); } } }