using CryptoExchange.Net.Authentication; using CryptoExchange.Net.Interfaces.Clients; using CryptoExchange.Net.Logging.Extensions; using CryptoExchange.Net.Objects; using CryptoExchange.Net.Objects.Options; using CryptoExchange.Net.Objects.Sockets; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace CryptoExchange.Net.Clients { /// /// Base for socket client implementations /// public abstract class BaseSocketClient : BaseClient, ISocketClient { #region fields /// /// Api clients in this client /// internal new List ApiClients => base.ApiClients.OfType().ToList(); /// /// If client is disposing /// protected bool _disposing; /// public int CurrentConnections => ApiClients.OfType().Sum(c => c.CurrentConnections); /// public int CurrentSubscriptions => ApiClients.OfType().Sum(s => s.CurrentSubscriptions); /// public double IncomingKbps => ApiClients.OfType().Sum(s => s.IncomingKbps); /// public new SocketExchangeOptions ClientOptions => (SocketExchangeOptions)base.ClientOptions; #endregion /// /// ctor /// /// Logger factory /// The name of the exchange this client is for protected BaseSocketClient(ILoggerFactory? loggerFactory, string name) : base(loggerFactory, name) { _logger = loggerFactory?.CreateLogger(name + ".SocketClient") ?? NullLoggerFactory.Instance.CreateLogger(name); LibraryHelpers.StaticLogger = loggerFactory?.CreateLogger("CryptoExchange"); } /// /// Unsubscribe an update subscription /// /// The id of the subscription to unsubscribe /// public virtual async Task UnsubscribeAsync(int subscriptionId) { foreach (var socket in ApiClients.OfType()) { var result = await socket.UnsubscribeAsync(subscriptionId).ConfigureAwait(false); if (result) break; } } /// /// Unsubscribe an update subscription /// /// The subscription to unsubscribe /// public virtual async Task UnsubscribeAsync(UpdateSubscription subscription) { if (subscription == null) throw new ArgumentNullException(nameof(subscription)); _logger.UnsubscribingSubscription(subscription.SocketId, subscription.Id); await subscription.CloseAsync().ConfigureAwait(false); } /// /// Unsubscribe all subscriptions /// /// public virtual async Task UnsubscribeAllAsync() { var tasks = new List(); foreach (var client in ApiClients.OfType()) tasks.Add(client.UnsubscribeAllAsync()); await Task.WhenAll(tasks.ToArray()).ConfigureAwait(false); } /// /// Reconnect all connections /// /// public virtual async Task ReconnectAsync() { _logger.ReconnectingAllConnections(CurrentConnections); var tasks = new List(); foreach (var client in ApiClients.OfType()) { tasks.Add(client.ReconnectAsync()); } await Task.WhenAll(tasks.ToArray()).ConfigureAwait(false); } /// /// Log the current state of connections and subscriptions /// public string GetSubscriptionsState() { var result = new StringBuilder(); foreach (var client in ApiClients.OfType().Where(c => c.CurrentSubscriptions > 0)) { result.AppendLine(client.GetSubscriptionsState()); } return result.ToString(); } /// /// Returns the state of all socket api clients /// /// public List GetSocketApiClientStates() { var result = new List(); foreach (var client in ApiClients.OfType()) { result.Add(client.GetState()); } return result; } /// /// Update options /// public virtual void SetOptions(UpdateOptions options) { foreach (var apiClient in ApiClients) apiClient.SetOptions(options); } } /// public abstract class BaseSocketClient : BaseSocketClient, ISocketClient where TEnvironment : TradeEnvironment where TApiCredentials : ApiCredentials { /// /// Api clients in this client /// internal new List> ApiClients => base.ApiClients.OfType>().ToList(); /// /// Provided client options /// public new SocketExchangeOptions ClientOptions => (SocketExchangeOptions)base.ClientOptions; /// /// ctor /// /// Logger factory /// The name of the API this client is for protected BaseSocketClient(ILoggerFactory? loggerFactory, string name) : base(loggerFactory, name) { } /// /// 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 public virtual void SetApiCredentials(TApiCredentials credentials) { foreach (var apiClient in ApiClients) apiClient.SetApiCredentials(credentials); } /// /// Update options /// public virtual void SetOptions(UpdateOptions options) { foreach (var apiClient in ApiClients) apiClient.SetOptions(options); } } }