diff --git a/CryptoExchange.Net/CryptoExchange.Net.xml b/CryptoExchange.Net/CryptoExchange.Net.xml index eb0f4f6..e8565c6 100644 --- a/CryptoExchange.Net/CryptoExchange.Net.xml +++ b/CryptoExchange.Net/CryptoExchange.Net.xml @@ -3036,7 +3036,7 @@ - + @@ -3609,6 +3609,11 @@ Connection lost event + + + Connection closed and no reconnect is happening + + Connecting restored event @@ -3809,6 +3814,12 @@ Event when the connection is lost. The socket will automatically reconnect when possible. + + + Event when the connection is closed. This event happens when reconnecting/resubscribing has failed too often based on the and options, + or is false + + Event when the connection is restored. Timespan parameter indicates the time the socket has been offline for before reconnecting. diff --git a/CryptoExchange.Net/OrderBook/SymbolOrderBook.cs b/CryptoExchange.Net/OrderBook/SymbolOrderBook.cs index f3661b2..db12bca 100644 --- a/CryptoExchange.Net/OrderBook/SymbolOrderBook.cs +++ b/CryptoExchange.Net/OrderBook/SymbolOrderBook.cs @@ -247,11 +247,16 @@ namespace CryptoExchange.Net.OrderBook subscription = startResult.Data; subscription.ConnectionLost += () => { - log.Write(LogLevel.Warning, $"{Id} order book {Symbol} connection lost"); Status = OrderBookStatus.Reconnecting; Reset(); }; + subscription.ConnectionClosed += () => + { + log.Write(LogLevel.Warning, $"{Id} order book {Symbol} disconnected"); + Status = OrderBookStatus.Disconnected; + StopAsync(); + }; subscription.ConnectionRestored += async time => await ResyncAsync().ConfigureAwait(false); Status = OrderBookStatus.Synced; @@ -336,6 +341,7 @@ namespace CryptoExchange.Net.OrderBook if(subscription != null) await subscription.CloseAsync().ConfigureAwait(false); + log.Write(LogLevel.Debug, $"{Id} order book {Symbol} stopped"); } /// diff --git a/CryptoExchange.Net/SocketClient.cs b/CryptoExchange.Net/SocketClient.cs index dc7f270..ba9683f 100644 --- a/CryptoExchange.Net/SocketClient.cs +++ b/CryptoExchange.Net/SocketClient.cs @@ -53,7 +53,7 @@ namespace CryptoExchange.Net public int? MaxReconnectTries { get; protected set; } /// public int? MaxResubscribeTries { get; protected set; } - /// + /// public int MaxConcurrentResubscriptionsPerSocket { get; protected set; } /// /// Delegate used for processing byte data received from socket connections before it is processed by handlers diff --git a/CryptoExchange.Net/Sockets/SocketConnection.cs b/CryptoExchange.Net/Sockets/SocketConnection.cs index ea44585..4d66804 100644 --- a/CryptoExchange.Net/Sockets/SocketConnection.cs +++ b/CryptoExchange.Net/Sockets/SocketConnection.cs @@ -23,6 +23,10 @@ namespace CryptoExchange.Net.Sockets /// public event Action? ConnectionLost; /// + /// Connection closed and no reconnect is happening + /// + public event Action? ConnectionClosed; + /// /// Connecting restored event /// public event Action? ConnectionRestored; @@ -127,17 +131,6 @@ namespace CryptoExchange.Net.Sockets Socket.Timeout = client.SocketNoDataTimeout; Socket.OnMessage += ProcessMessage; - Socket.OnClose += () => - { - if (lostTriggered) - return; - - DisconnectTime = DateTime.UtcNow; - lostTriggered = true; - - if (ShouldReconnect) - ConnectionLost?.Invoke(); - }; Socket.OnClose += SocketOnClose; Socket.OnOpen += () => { @@ -315,6 +308,13 @@ namespace CryptoExchange.Net.Sockets if (Socket.Reconnecting) return; // Already reconnecting + DisconnectTime = DateTime.UtcNow; + if (!lostTriggered) + { + lostTriggered = true; + ConnectionLost?.Invoke(); + } + Socket.Reconnecting = true; log.Write(LogLevel.Information, $"Socket {Socket.Id} Connection lost, will try to reconnect after {socketClient.ReconnectInterval}"); @@ -345,6 +345,7 @@ namespace CryptoExchange.Net.Sockets socketClient.sockets.TryRemove(Socket.Id, out _); Closed?.Invoke(); + _ = Task.Run(() => ConnectionClosed?.Invoke()); break; } @@ -373,6 +374,7 @@ namespace CryptoExchange.Net.Sockets socketClient.sockets.TryRemove(Socket.Id, out _); Closed?.Invoke(); + _ = Task.Run(() => ConnectionClosed?.Invoke()); } else log.Write(LogLevel.Debug, $"Socket {Socket.Id} resubscribing all subscriptions failed on reconnected socket{(socketClient.MaxResubscribeTries != null ? $", try {ResubscribeTry}/{socketClient.MaxResubscribeTries}" : "")}. Disconnecting and reconnecting."); @@ -397,6 +399,9 @@ namespace CryptoExchange.Net.Sockets } else { + if (!socketClient.AutoReconnect && ShouldReconnect) + _ = Task.Run(() => ConnectionClosed?.Invoke()); + // No reconnecting needed log.Write(LogLevel.Information, $"Socket {Socket.Id} closed"); if (socketClient.sockets.ContainsKey(Socket.Id)) diff --git a/CryptoExchange.Net/Sockets/UpdateSubscription.cs b/CryptoExchange.Net/Sockets/UpdateSubscription.cs index 0d352ab..b3143ef 100644 --- a/CryptoExchange.Net/Sockets/UpdateSubscription.cs +++ b/CryptoExchange.Net/Sockets/UpdateSubscription.cs @@ -21,6 +21,16 @@ namespace CryptoExchange.Net.Sockets remove => connection.ConnectionLost -= value; } + /// + /// Event when the connection is closed. This event happens when reconnecting/resubscribing has failed too often based on the and options, + /// or is false + /// + public event Action ConnectionClosed + { + add => connection.ConnectionClosed += value; + remove => connection.ConnectionClosed -= value; + } + /// /// Event when the connection is restored. Timespan parameter indicates the time the socket has been offline for before reconnecting. /// Note that when the executing code is suspended and resumed at a later period (for example laptop going to sleep) the disconnect time will be incorrect as the diconnect