diff --git a/CryptoExchange.Net/Clients/BaseSocketClient.cs b/CryptoExchange.Net/Clients/BaseSocketClient.cs index 503604a..1b8d37c 100644 --- a/CryptoExchange.Net/Clients/BaseSocketClient.cs +++ b/CryptoExchange.Net/Clients/BaseSocketClient.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Text; using System.Threading.Tasks; using CryptoExchange.Net.Authentication; using CryptoExchange.Net.Interfaces; @@ -101,16 +102,10 @@ namespace CryptoExchange.Net /// public string GetSubscriptionsState() { - //var sb = new StringBuilder(); - //sb.AppendLine($"{socketConnections.Count} connections, {CurrentSubscriptions} subscriptions, kbps: {IncomingKbps}"); - //foreach(var connection in socketConnections) - //{ - // sb.AppendLine($" Connection {connection.Key}: {connection.Value.SubscriptionCount} subscriptions, status: {connection.Value.Status}, authenticated: {connection.Value.Authenticated}, kbps: {connection.Value.IncomingKbps}"); - // foreach (var subscription in connection.Value.Subscriptions) - // sb.AppendLine($" Subscription {subscription.Id}, authenticated: {subscription.Authenticated}, confirmed: {subscription.Confirmed}"); - //} - //return sb.ToString(); - return ""; + var result = new StringBuilder(); + foreach(var client in ApiClients.OfType()) + result.AppendLine(client.GetSubscriptionsState()); + return result.ToString(); } } } diff --git a/CryptoExchange.Net/Clients/SocketApiClient.cs b/CryptoExchange.Net/Clients/SocketApiClient.cs index 383bb19..68da362 100644 --- a/CryptoExchange.Net/Clients/SocketApiClient.cs +++ b/CryptoExchange.Net/Clients/SocketApiClient.cs @@ -378,6 +378,9 @@ namespace CryptoExchange.Net if (!connectResult) return new CallResult(connectResult.Error!); + if (Options.DelayAfterConnect != TimeSpan.Zero) + await Task.Delay(Options.DelayAfterConnect).ConfigureAwait(false); + if (!authenticated || socket.Authenticated) return new CallResult(true); @@ -541,6 +544,16 @@ namespace CryptoExchange.Net return Task.FromResult(connection.ConnectionUri); } + /// + /// Update the original request to send when the connection is restored after disconnecting. Can be used to update an authentication token for example. + /// + /// The original request + /// + public virtual Task> RevitalizeRequestAsync(object request) + { + return Task.FromResult(new CallResult(request)); + } + /// /// Gets a connection for a new subscription or query. Can be an existing if there are open position or a new one. /// diff --git a/CryptoExchange.Net/Objects/Options.cs b/CryptoExchange.Net/Objects/Options.cs index 533478d..c41b6df 100644 --- a/CryptoExchange.Net/Objects/Options.cs +++ b/CryptoExchange.Net/Objects/Options.cs @@ -268,6 +268,11 @@ namespace CryptoExchange.Net.Objects /// public int? MaxSocketConnections { get; set; } + /// + /// The time to wait after connecting a socket before sending messages. Can be used for API's which will rate limit if you subscribe directly after connecting. + /// + public TimeSpan DelayAfterConnect = TimeSpan.Zero; + /// /// ctor /// diff --git a/CryptoExchange.Net/Sockets/CryptoExchangeWebSocketClient.cs b/CryptoExchange.Net/Sockets/CryptoExchangeWebSocketClient.cs index 9f99b48..012a56f 100644 --- a/CryptoExchange.Net/Sockets/CryptoExchangeWebSocketClient.cs +++ b/CryptoExchange.Net/Sockets/CryptoExchangeWebSocketClient.cs @@ -165,7 +165,7 @@ namespace CryptoExchange.Net.Sockets socket.Options.KeepAliveInterval = Parameters.KeepAliveInterval ?? TimeSpan.Zero; socket.Options.SetBuffer(65536, 65536); // Setting it to anything bigger than 65536 throws an exception in .net framework if (Parameters.Proxy != null) - SetProxy(Parameters.Proxy); + SetProxy(socket, Parameters.Proxy); } catch (PlatformNotSupportedException) { @@ -739,22 +739,23 @@ namespace CryptoExchange.Net.Sockets /// /// Set proxy on socket /// + /// /// /// - protected virtual void SetProxy(ApiProxy proxy) + protected virtual void SetProxy(ClientWebSocket socket, ApiProxy proxy) { if (!Uri.TryCreate($"{proxy.Host}:{proxy.Port}", UriKind.Absolute, out var uri)) throw new ArgumentException("Proxy settings invalid, {proxy.Host}:{proxy.Port} not a valid URI", nameof(proxy)); - _socket.Options.Proxy = uri?.Scheme == null - ? _socket.Options.Proxy = new WebProxy(proxy.Host, proxy.Port) - : _socket.Options.Proxy = new WebProxy + socket.Options.Proxy = uri?.Scheme == null + ? socket.Options.Proxy = new WebProxy(proxy.Host, proxy.Port) + : socket.Options.Proxy = new WebProxy { Address = uri }; if (proxy.Login != null) - _socket.Options.Proxy.Credentials = new NetworkCredential(proxy.Login, proxy.Password); + socket.Options.Proxy.Credentials = new NetworkCredential(proxy.Login, proxy.Password); } } diff --git a/CryptoExchange.Net/Sockets/SocketConnection.cs b/CryptoExchange.Net/Sockets/SocketConnection.cs index ab4050e..44eb0a5 100644 --- a/CryptoExchange.Net/Sockets/SocketConnection.cs +++ b/CryptoExchange.Net/Sockets/SocketConnection.cs @@ -253,6 +253,7 @@ namespace CryptoExchange.Net.Sockets var reconnectSuccessful = await ProcessReconnectAsync().ConfigureAwait(false); if (!reconnectSuccessful) { + _log.Write(LogLevel.Warning, "Failed reconnect processing, reconnecting again"); await _socket.ReconnectAsync().ConfigureAwait(false); } else @@ -637,6 +638,16 @@ namespace CryptoExchange.Net.Sockets } } + foreach(var subscription in subscriptionList.Where(s => s.Request != null)) + { + var result = await ApiClient.RevitalizeRequestAsync(subscription.Request!).ConfigureAwait(false); + if (!result) + { + _log.Write(LogLevel.Warning, "Failed request revitalization: " + result.Error); + return result.As(false); + } + } + // Foreach subscription which is subscribed by a subscription request we will need to resend that request to resubscribe for (var i = 0; i < subscriptionList.Count; i += ApiClient.Options.MaxConcurrentResubscriptionsPerSocket) {