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