using CryptoExchange.Net.Interfaces; using CryptoExchange.Net.Objects; using CryptoExchange.Net.Objects.Sockets; using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; namespace CryptoExchange.Net.Sockets { /// /// Socket subscription /// public abstract class Subscription : IMessageProcessor { /// /// Subscription id /// public int Id { get; set; } /// /// Total amount of invocations /// public int TotalInvocations { get; set; } /// /// Amount of invocation during this connection /// public int ConnectionInvocations { get; set; } /// /// Is it a user subscription /// public bool UserSubscription { get; set; } /// /// Has the subscription been confirmed /// public bool Confirmed { get; set; } /// /// Is the subscription closed /// public bool Closed { get; set; } /// /// Logger /// protected readonly ILogger _logger; /// /// If the subscription is a private subscription and needs authentication /// public bool Authenticated { get; } /// /// Strings to match this subscription to a received message /// public abstract HashSet ListenerIdentifiers { get; set; } /// /// Cancellation token registration /// public CancellationTokenRegistration? CancellationTokenRegistration { get; set; } /// /// Exception event /// public event Action? Exception; /// /// Get the deserialization type for this message /// /// /// public abstract Type? GetMessageType(IMessageAccessor message); /// /// ctor /// /// /// /// public Subscription(ILogger logger, bool authenticated, bool userSubscription = true) { _logger = logger; Authenticated = authenticated; UserSubscription = userSubscription; Id = ExchangeHelpers.NextId(); } /// /// Get the subscribe query to send when subscribing /// /// public abstract Query? GetSubQuery(SocketConnection connection); /// /// Handle a subscription query response /// /// public virtual void HandleSubQueryResponse(object message) { } /// /// Handle an unsubscription query response /// /// public virtual void HandleUnsubQueryResponse(object message) { } /// /// Get the unsubscribe query to send when unsubscribing /// /// public abstract Query? GetUnsubQuery(); /// public virtual CallResult Deserialize(IMessageAccessor message, Type type) => message.Deserialize(type); /// /// Handle an update message /// /// /// /// public Task Handle(SocketConnection connection, DataEvent message) { ConnectionInvocations++; TotalInvocations++; return Task.FromResult(DoHandleMessage(connection, message)); } /// /// Reset the subscription /// public void Reset() { Confirmed = false; DoHandleReset(); } /// /// Connection has been reset, do any logic for resetting the subscription /// public virtual void DoHandleReset() { } /// /// Handle the update message /// /// /// /// public abstract CallResult DoHandleMessage(SocketConnection connection, DataEvent message); /// /// Invoke the exception event /// /// public void InvokeExceptionHandler(Exception e) { Exception?.Invoke(e); } /// /// State of this subscription /// /// The id of the subscription /// True when the subscription query is handled (either accepted or rejected) /// Number of times this subscription got a message /// Identifiers the subscription is listening to public record SubscriptionState( int Id, bool Confirmed, int Invocations, HashSet Identifiers ); /// /// Get the state of this subscription /// /// public SubscriptionState GetState() { return new SubscriptionState(Id, Confirmed, TotalInvocations, ListenerIdentifiers); } } /// public abstract class Subscription : Subscription { /// /// ctor /// /// /// protected Subscription(ILogger logger, bool authenticated) : base(logger, authenticated) { } /// public override void HandleSubQueryResponse(object message) => HandleSubQueryResponse((TSubResponse)message); /// /// Handle a subscription query response /// /// public virtual void HandleSubQueryResponse(TSubResponse message) { } /// public override void HandleUnsubQueryResponse(object message) => HandleUnsubQueryResponse((TUnsubResponse)message); /// /// Handle an unsubscription query response /// /// public virtual void HandleUnsubQueryResponse(TUnsubResponse message) { } } }