diff --git a/CryptoExchange.Net/Objects/Sockets/UpdateSubscription.cs b/CryptoExchange.Net/Objects/Sockets/UpdateSubscription.cs index e627c43..bfca2dc 100644 --- a/CryptoExchange.Net/Objects/Sockets/UpdateSubscription.cs +++ b/CryptoExchange.Net/Objects/Sockets/UpdateSubscription.cs @@ -1,5 +1,7 @@ using CryptoExchange.Net.Sockets; using System; +using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; namespace CryptoExchange.Net.Objects.Sockets @@ -12,13 +14,21 @@ namespace CryptoExchange.Net.Objects.Sockets private readonly SocketConnection _connection; private readonly Subscription _listener; + private object _eventLock = new object(); + private List _connectionClosedEventHandlers = new List(); + private List _connectionLostEventHandlers = new List(); + private List> _resubscribeFailedEventHandlers = new List>(); + private List> _connectionRestoredEventHandlers = new List>(); + private List _activityPausedEventHandlers = new List(); + private List _activityUnpausedEventHandlers = new List(); + /// /// Event when the connection is lost. The socket will automatically reconnect when possible. /// public event Action ConnectionLost { - add => _connection.ConnectionLost += value; - remove => _connection.ConnectionLost -= value; + add { lock (_eventLock) _connectionLostEventHandlers.Add(value); } + remove { lock (_eventLock) _connectionLostEventHandlers.Remove(value); } } /// @@ -26,8 +36,8 @@ namespace CryptoExchange.Net.Objects.Sockets /// public event Action ConnectionClosed { - add => _connection.ConnectionClosed += value; - remove => _connection.ConnectionClosed -= value; + add { lock (_eventLock) _connectionClosedEventHandlers.Add(value); } + remove { lock (_eventLock) _connectionClosedEventHandlers.Remove(value); } } /// @@ -35,8 +45,8 @@ namespace CryptoExchange.Net.Objects.Sockets /// public event Action ResubscribingFailed { - add => _connection.ResubscribingFailed += value; - remove => _connection.ResubscribingFailed -= value; + add { lock (_eventLock) _resubscribeFailedEventHandlers.Add(value); } + remove { lock (_eventLock) _resubscribeFailedEventHandlers.Remove(value); } } /// @@ -46,8 +56,8 @@ namespace CryptoExchange.Net.Objects.Sockets /// public event Action ConnectionRestored { - add => _connection.ConnectionRestored += value; - remove => _connection.ConnectionRestored -= value; + add { lock (_eventLock) _connectionRestoredEventHandlers.Add(value); } + remove { lock (_eventLock) _connectionRestoredEventHandlers.Remove(value); } } /// @@ -55,8 +65,8 @@ namespace CryptoExchange.Net.Objects.Sockets /// public event Action ActivityPaused { - add => _connection.ActivityPaused += value; - remove => _connection.ActivityPaused -= value; + add { lock (_eventLock) _activityPausedEventHandlers.Add(value); } + remove { lock (_eventLock) _activityPausedEventHandlers.Remove(value); } } /// @@ -64,8 +74,8 @@ namespace CryptoExchange.Net.Objects.Sockets /// public event Action ActivityUnpaused { - add => _connection.ActivityUnpaused += value; - remove => _connection.ActivityUnpaused -= value; + add { lock (_eventLock) _activityUnpausedEventHandlers.Add(value); } + remove { lock (_eventLock) _activityUnpausedEventHandlers.Remove(value); } } /// @@ -95,7 +105,85 @@ namespace CryptoExchange.Net.Objects.Sockets public UpdateSubscription(SocketConnection connection, Subscription subscription) { _connection = connection; + _connection.ConnectionClosed += HandleConnectionClosedEvent; + _connection.ConnectionLost += HandleConnectionLostEvent; + _connection.ConnectionRestored += HandleConnectionRestoredEvent; + _connection.ResubscribingFailed += HandleResubscribeFailedEvent; + _connection.ActivityPaused += HandlePausedEvent; + _connection.ActivityUnpaused += HandleUnpausedEvent; + _listener = subscription; + _listener.Unsubscribed += HandleUnsubscribed; + } + + private void HandleUnsubscribed() + { + _connection.ConnectionClosed -= HandleConnectionClosedEvent; + _connection.ConnectionLost -= HandleConnectionLostEvent; + _connection.ConnectionRestored -= HandleConnectionRestoredEvent; + _connection.ResubscribingFailed -= HandleResubscribeFailedEvent; + _connection.ActivityPaused -= HandlePausedEvent; + _connection.ActivityUnpaused -= HandleUnpausedEvent; + } + + private void HandleConnectionClosedEvent() + { + List handlers; + lock (_eventLock) + handlers = _connectionClosedEventHandlers.ToList(); + + foreach(var callback in handlers) + callback(); + } + + private void HandleConnectionLostEvent() + { + List handlers; + lock (_eventLock) + handlers = _connectionLostEventHandlers.ToList(); + + foreach (var callback in handlers) + callback(); + } + + private void HandleConnectionRestoredEvent(TimeSpan period) + { + List> handlers; + lock (_eventLock) + handlers = _connectionRestoredEventHandlers.ToList(); + + foreach (var callback in handlers) + callback(period); + } + + private void HandleResubscribeFailedEvent(Error error) + { + List> handlers; + lock (_eventLock) + handlers = _resubscribeFailedEventHandlers.ToList(); + + foreach (var callback in handlers) + callback(error); + } + + private void HandlePausedEvent() + { + List handlers; + lock (_eventLock) + handlers = _activityPausedEventHandlers.ToList(); + + foreach (var callback in handlers) + callback(); + } + + private void HandleUnpausedEvent() + { + List handlers; + lock (_eventLock) + handlers = _activityUnpausedEventHandlers.ToList(); + + foreach (var callback in handlers) + callback(); } /// diff --git a/CryptoExchange.Net/Sockets/SocketConnection.cs b/CryptoExchange.Net/Sockets/SocketConnection.cs index 9c8d84e..32f90d8 100644 --- a/CryptoExchange.Net/Sockets/SocketConnection.cs +++ b/CryptoExchange.Net/Sockets/SocketConnection.cs @@ -706,6 +706,8 @@ namespace CryptoExchange.Net.Sockets lock (_listenersLock) _listeners.Remove(subscription); + + subscription.InvokeUnsubscribedHandler(); } /// diff --git a/CryptoExchange.Net/Sockets/Subscription.cs b/CryptoExchange.Net/Sockets/Subscription.cs index df0b66b..612fc4c 100644 --- a/CryptoExchange.Net/Sockets/Subscription.cs +++ b/CryptoExchange.Net/Sockets/Subscription.cs @@ -74,6 +74,10 @@ namespace CryptoExchange.Net.Sockets /// Exception event /// public event Action? Exception; + /// + /// Listener unsubscribed event + /// + public event Action? Unsubscribed; /// /// Subscription topic @@ -181,6 +185,14 @@ namespace CryptoExchange.Net.Sockets Exception?.Invoke(e); } + /// + /// Invoke the unsubscribed event + /// + public void InvokeUnsubscribedHandler() + { + Unsubscribed?.Invoke(); + } + /// /// State of this subscription ///