using CryptoExchange.Net.Authentication; using CryptoExchange.Net.Objects; using CryptoExchange.Net.Objects.Options; using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; using System.Net; using System.Net.Http; namespace CryptoExchange.Net { /// /// Helpers for client libraries /// public static class LibraryHelpers { private static ILogger? _staticLogger; /// /// Static logger /// public static ILogger? StaticLogger { get => _staticLogger; internal set { if (_staticLogger != null) return; _staticLogger = value; } } /// /// Client order id separator /// public const string ClientOrderIdSeparator = "JK"; private static Dictionary _defaultClientReferences = new Dictionary() { { "Binance.Spot", "x-VICEW9VV" }, { "Binance.Futures", "x-d63tKbx3" }, { "BingX", "easytrading" }, { "Bitfinex", "kCCe-CNBO" }, { "Bitget", "6x21p" }, { "BitMart", "EASYTRADING0001" }, { "BitMEX", "Sent from JKorf" }, { "BloFin", "5c07cf695885c282" }, { "Bybit", "Zx000356" }, { "CoinEx", "x-147866029-" }, { "GateIo", "copytraderpw" }, { "HTX", "AA1ef14811" }, { "Kucoin.FuturesName", "Easytradingfutures" }, { "Kucoin.FuturesKey", "9e08c05f-454d-4580-82af-2f4c7027fd00" }, { "Kucoin.SpotName", "Easytrading" }, { "Kucoin.SpotKey", "f8ae62cb-2b3d-420c-8c98-e1c17dd4e30a" }, { "Mexc", "EASYT" }, { "OKX", "1425d83a94fbBCDE" }, { "Weex", "b-WEEX111124-" }, { "XT", "4XWeqN10M1fcoI5L" }, }; /// /// Apply broker id to a client order id /// /// /// /// /// /// public static string ApplyBrokerId(string? clientOrderId, string brokerId, int maxLength, bool allowValueAdjustment) { var reservedLength = brokerId.Length + ClientOrderIdSeparator.Length; if (clientOrderId?.Length + reservedLength > maxLength) return clientOrderId!; if (!string.IsNullOrEmpty(clientOrderId)) { if (allowValueAdjustment) clientOrderId = brokerId + ClientOrderIdSeparator + clientOrderId; return clientOrderId!; } else { clientOrderId = ExchangeHelpers.AppendRandomString(brokerId + ClientOrderIdSeparator, maxLength); } return clientOrderId; } /// /// Get the client reference for an exchange if available /// public static string GetClientReference(Func optionsReference, string exchange, string? topic = null) { var optionsValue = optionsReference(); if (!string.IsNullOrEmpty(optionsValue)) return optionsValue!; var key = exchange; if (topic != null) key += "." + topic; return _defaultClientReferences.TryGetValue(key, out var id) ? id : throw new KeyNotFoundException($"{exchange} not found in configuration"); } /// /// Create a new HttpMessageHandler instance /// public static HttpMessageHandler CreateHttpClientMessageHandler(RestExchangeOptions options) { #if NET5_0_OR_GREATER var socketHandler = new SocketsHttpHandler(); try { if (options.HttpKeepAliveInterval != null && options.HttpKeepAliveInterval != TimeSpan.Zero) { socketHandler.KeepAlivePingPolicy = HttpKeepAlivePingPolicy.Always; socketHandler.KeepAlivePingDelay = options.HttpKeepAliveInterval.Value; socketHandler.KeepAlivePingTimeout = TimeSpan.FromSeconds(10); } socketHandler.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate; socketHandler.DefaultProxyCredentials = CredentialCache.DefaultCredentials; socketHandler.EnableMultipleHttp2Connections = options.HttpEnableMultipleHttp2Connections; socketHandler.PooledConnectionLifetime = options.HttpPooledConnectionLifetime; socketHandler.PooledConnectionIdleTimeout = options.HttpPooledConnectionIdleTimeout; socketHandler.MaxConnectionsPerServer = options.HttpMaxConnectionsPerServer; } catch (PlatformNotSupportedException) { } catch (NotImplementedException) { } // Mono runtime throws NotImplementedException if (options.Proxy != null) { socketHandler.Proxy = new WebProxy { Address = new Uri($"{options.Proxy.Host}:{options.Proxy.Port}"), Credentials = options.Proxy.Password == null ? null : new NetworkCredential(options.Proxy.Login, options.Proxy.Password) }; } return socketHandler; #else var httpHandler = new HttpClientHandler(); try { httpHandler.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate; httpHandler.DefaultProxyCredentials = CredentialCache.DefaultCredentials; } catch (PlatformNotSupportedException) { } catch (NotImplementedException) { } // Mono runtime throws NotImplementedException if (options.Proxy != null) { httpHandler.Proxy = new WebProxy { Address = new Uri($"{options.Proxy.Host}:{options.Proxy.Port}"), Credentials = options.Proxy.Password == null ? null : new NetworkCredential(options.Proxy.Login, options.Proxy.Password) }; } return httpHandler; #endif } } }