diff --git a/CryptoExchange.Net.UnitTests/TestImplementations/Sockets/TestChannelQuery.cs b/CryptoExchange.Net.UnitTests/TestImplementations/Sockets/TestChannelQuery.cs deleted file mode 100644 index 69341ee..0000000 --- a/CryptoExchange.Net.UnitTests/TestImplementations/Sockets/TestChannelQuery.cs +++ /dev/null @@ -1,50 +0,0 @@ -using CryptoExchange.Net.Objects; -using CryptoExchange.Net.Objects.Errors; -using CryptoExchange.Net.Objects.Sockets; -using CryptoExchange.Net.Sockets; -using CryptoExchange.Net.Sockets.Default; -using System; -using System.Text.Json.Serialization; - -namespace CryptoExchange.Net.UnitTests.TestImplementations.Sockets -{ - internal class SubResponse - { - - [JsonPropertyName("action")] - public string Action { get; set; } = null!; - - [JsonPropertyName("channel")] - public string Channel { get; set; } = null!; - - [JsonPropertyName("status")] - public string Status { get; set; } = null!; - } - - internal class UnsubResponse - { - [JsonPropertyName("action")] - public string Action { get; set; } = null!; - - [JsonPropertyName("status")] - public string Status { get; set; } = null!; - } - - internal class TestChannelQuery : Query - { - public TestChannelQuery(string channel, string request, bool authenticated, int weight = 1) : base(request, authenticated, weight) - { - MessageMatcher = MessageMatcher.Create(request + "-" + channel, HandleMessage); - } - - public CallResult HandleMessage(SocketConnection connection, DateTime time, string? originalData, SubResponse message) - { - if (!message.Status.Equals("confirmed", StringComparison.OrdinalIgnoreCase)) - { - return new CallResult(new ServerError(ErrorInfo.Unknown with { Message = message.Status })); - } - - return new CallResult(message, originalData, null); - } - } -} diff --git a/CryptoExchange.Net.UnitTests/TestImplementations/Sockets/TestQuery.cs b/CryptoExchange.Net.UnitTests/TestImplementations/Sockets/TestQuery.cs deleted file mode 100644 index 48a41fb..0000000 --- a/CryptoExchange.Net.UnitTests/TestImplementations/Sockets/TestQuery.cs +++ /dev/null @@ -1,12 +0,0 @@ -using CryptoExchange.Net.Sockets; - -namespace CryptoExchange.Net.UnitTests.TestImplementations.Sockets -{ - internal class TestQuery : Query - { - public TestQuery(string identifier, object request, bool authenticated, int weight = 1) : base(request, authenticated, weight) - { - MessageMatcher = MessageMatcher.Create(identifier); - } - } -} diff --git a/CryptoExchange.Net.UnitTests/TestImplementations/Sockets/TestSubscription.cs b/CryptoExchange.Net.UnitTests/TestImplementations/Sockets/TestSubscription.cs deleted file mode 100644 index d5829a6..0000000 --- a/CryptoExchange.Net.UnitTests/TestImplementations/Sockets/TestSubscription.cs +++ /dev/null @@ -1,30 +0,0 @@ -using CryptoExchange.Net.Objects; -using CryptoExchange.Net.Objects.Sockets; -using CryptoExchange.Net.Sockets; -using CryptoExchange.Net.Sockets.Default; -using Microsoft.Extensions.Logging; -using System; - -namespace CryptoExchange.Net.UnitTests.TestImplementations.Sockets -{ - internal class TestSubscription : Subscription - { - private readonly Action> _handler; - - public TestSubscription(ILogger logger, Action> handler) : base(logger, false) - { - _handler = handler; - - MessageMatcher = MessageMatcher.Create("update-topic", DoHandleMessage); - } - - public CallResult DoHandleMessage(SocketConnection connection, DateTime receiveTime, string? originalData, T message) - { - _handler.Invoke(new DataEvent("Test", message, receiveTime, originalData)); - return new CallResult(null); - } - - protected override Query GetSubQuery(SocketConnection connection) => new TestQuery("sub", new object(), false, 1); - protected override Query GetUnsubQuery(SocketConnection connection) => new TestQuery("unsub", new object(), false, 1); - } -} diff --git a/CryptoExchange.Net.UnitTests/TestImplementations/Sockets/TestSubscriptionWithResponseCheck.cs b/CryptoExchange.Net.UnitTests/TestImplementations/Sockets/TestSubscriptionWithResponseCheck.cs deleted file mode 100644 index d1c6ddb..0000000 --- a/CryptoExchange.Net.UnitTests/TestImplementations/Sockets/TestSubscriptionWithResponseCheck.cs +++ /dev/null @@ -1,32 +0,0 @@ -using CryptoExchange.Net.Objects; -using CryptoExchange.Net.Objects.Sockets; -using CryptoExchange.Net.Sockets; -using CryptoExchange.Net.Sockets.Default; -using Microsoft.Extensions.Logging; -using Moq; -using System; - -namespace CryptoExchange.Net.UnitTests.TestImplementations.Sockets -{ - internal class TestSubscriptionWithResponseCheck : Subscription - { - private readonly Action> _handler; - private readonly string _channel; - - public TestSubscriptionWithResponseCheck(string channel, Action> handler) : base(Mock.Of(), false) - { - MessageMatcher = MessageMatcher.Create(channel, DoHandleMessage); - _handler = handler; - _channel = channel; - } - - public CallResult DoHandleMessage(SocketConnection connection, DateTime receiveTime, string? originalData, T message) - { - _handler.Invoke(new DataEvent("Test", message, receiveTime, originalData)); - return new CallResult(null); - } - - protected override Query GetSubQuery(SocketConnection connection) => new TestChannelQuery(_channel, "subscribe", false, 1); - protected override Query GetUnsubQuery(SocketConnection connection) => new TestChannelQuery(_channel, "unsubscribe", false, 1); - } -} diff --git a/CryptoExchange.Net.UnitTests/TestImplementations/TestBaseClient.cs b/CryptoExchange.Net.UnitTests/TestImplementations/TestBaseClient.cs index d563c3e..2d08c2b 100644 --- a/CryptoExchange.Net.UnitTests/TestImplementations/TestBaseClient.cs +++ b/CryptoExchange.Net.UnitTests/TestImplementations/TestBaseClient.cs @@ -86,4 +86,14 @@ namespace CryptoExchange.Net.UnitTests public string GetKey() => _credentials.Key; public string GetSecret() => _credentials.Secret; } + + public class TestEnvironment : TradeEnvironment + { + public string TestAddress { get; } + + public TestEnvironment(string name, string url) : base(name) + { + TestAddress = url; + } + } } diff --git a/CryptoExchange.Net.UnitTests/TestImplementations/TestSocket.cs b/CryptoExchange.Net.UnitTests/TestImplementations/TestSocket.cs deleted file mode 100644 index c3408de..0000000 --- a/CryptoExchange.Net.UnitTests/TestImplementations/TestSocket.cs +++ /dev/null @@ -1,132 +0,0 @@ -//using System; -//using System.IO; -//using System.Net.WebSockets; -//using System.Security.Authentication; -//using System.Text; -//using System.Threading.Tasks; -//using CryptoExchange.Net.Interfaces; -//using CryptoExchange.Net.Objects; - -//namespace CryptoExchange.Net.UnitTests.TestImplementations -//{ -// public class TestSocket: IWebsocket -// { -// public bool CanConnect { get; set; } -// public bool Connected { get; set; } - -// public event Func OnClose; -//#pragma warning disable 0067 -// public event Func OnReconnected; -// public event Func OnReconnecting; -// public event Func OnRequestRateLimited; -//#pragma warning restore 0067 -// public event Func OnRequestSent; -// public event Func, Task> OnStreamMessage; -// public event Func OnError; -// public event Func OnOpen; -// public Func> GetReconnectionUrl { get; set; } - -// public int Id { get; } -// public bool ShouldReconnect { get; set; } -// public TimeSpan Timeout { get; set; } -// public Func DataInterpreterString { get; set; } -// public Func DataInterpreterBytes { get; set; } -// public DateTime? DisconnectTime { get; set; } -// public string Url { get; } -// public bool IsClosed => !Connected; -// public bool IsOpen => Connected; -// public bool PingConnection { get; set; } -// public TimeSpan PingInterval { get; set; } -// public SslProtocols SSLProtocols { get; set; } -// public Encoding Encoding { get; set; } - -// public int ConnectCalls { get; private set; } -// public bool Reconnecting { get; set; } -// public string Origin { get; set; } -// public int? RatelimitPerSecond { get; set; } - -// public double IncomingKbps => throw new NotImplementedException(); - -// public Uri Uri => new Uri(""); - -// public TimeSpan KeepAliveInterval { get; set; } - -// public static int lastId = 0; -// public static object lastIdLock = new object(); - -// public TestSocket() -// { -// lock (lastIdLock) -// { -// Id = lastId + 1; -// lastId++; -// } -// } - -// public Task ConnectAsync() -// { -// Connected = CanConnect; -// ConnectCalls++; -// if (CanConnect) -// InvokeOpen(); -// return Task.FromResult(CanConnect ? new CallResult(null) : new CallResult(new CantConnectError())); -// } - -// public bool Send(int requestId, string data, int weight) -// { -// if(!Connected) -// throw new Exception("Socket not connected"); -// OnRequestSent?.Invoke(requestId); -// return true; -// } - -// public void Reset() -// { -// } - -// public Task CloseAsync() -// { -// Connected = false; -// DisconnectTime = DateTime.UtcNow; -// OnClose?.Invoke(); -// return Task.FromResult(0); -// } - -// public void SetProxy(string host, int port) -// { -// throw new NotImplementedException(); -// } -// public void Dispose() -// { -// } - -// public void InvokeClose() -// { -// Connected = false; -// DisconnectTime = DateTime.UtcNow; -// Reconnecting = true; -// OnClose?.Invoke(); -// } - -// public void InvokeOpen() -// { -// OnOpen?.Invoke(); -// } - -// public void InvokeMessage(string data) -// { -// OnStreamMessage?.Invoke(WebSocketMessageType.Text, new ReadOnlyMemory(Encoding.UTF8.GetBytes(data))).Wait(); -// } - -// public void SetProxy(ApiProxy proxy) -// { -// throw new NotImplementedException(); -// } - -// public void InvokeError(Exception error) -// { -// OnError?.Invoke(error); -// } -// public Task ReconnectAsync() => Task.CompletedTask; -// } -//} diff --git a/CryptoExchange.Net.UnitTests/TestImplementations/TestSocketClient.cs b/CryptoExchange.Net.UnitTests/TestImplementations/TestSocketClient.cs deleted file mode 100644 index dae9cea..0000000 --- a/CryptoExchange.Net.UnitTests/TestImplementations/TestSocketClient.cs +++ /dev/null @@ -1,148 +0,0 @@ -//using System; -//using System.Collections.Generic; -//using System.Threading; -//using System.Threading.Tasks; -//using CryptoExchange.Net.Authentication; -//using CryptoExchange.Net.Clients; -//using CryptoExchange.Net.Converters.MessageParsing; -//using CryptoExchange.Net.Interfaces; -//using CryptoExchange.Net.Objects; -//using CryptoExchange.Net.Objects.Options; -//using CryptoExchange.Net.Objects.Sockets; -//using CryptoExchange.Net.Sockets; -//using CryptoExchange.Net.UnitTests.TestImplementations.Sockets; -//using Microsoft.Extensions.Logging; -//using Moq; -//using CryptoExchange.Net.Testing.Implementations; -//using CryptoExchange.Net.SharedApis; -//using Microsoft.Extensions.Options; -//using CryptoExchange.Net.Converters.SystemTextJson; -//using System.Net.WebSockets; -//using System.Text.Json; -//using CryptoExchange.Net.Converters.MessageParsing.DynamicConverters; - -//namespace CryptoExchange.Net.UnitTests.TestImplementations -//{ -// internal class TestSocketClient: BaseSocketClient -// { -// public TestSubSocketClient SubClient { get; } - -// /// -// /// Create a new instance of TestSocketClient -// /// -// /// Configure the options to use for this client -// public TestSocketClient(Action optionsDelegate = null) -// : this(Options.Create(ApplyOptionsDelegate(optionsDelegate)), null) -// { -// } - -// public TestSocketClient(IOptions options, ILoggerFactory loggerFactory = null) : base(loggerFactory, "Test") -// { -// Initialize(options.Value); - -// SubClient = AddApiClient(new TestSubSocketClient(options.Value, options.Value.SubOptions)); -// SubClient.SocketFactory = new Mock().Object; -// Mock.Get(SubClient.SocketFactory).Setup(f => f.CreateWebsocket(It.IsAny(), It.IsAny())).Returns(new TestSocket("https://test.com")); -// } - -// public TestSocket CreateSocket() -// { -// Mock.Get(SubClient.SocketFactory).Setup(f => f.CreateWebsocket(It.IsAny(), It.IsAny())).Returns(new TestSocket("https://test.com")); -// return (TestSocket)SubClient.CreateSocketInternal("https://localhost:123/"); -// } - -// } - -using CryptoExchange.Net.Objects; - -public class TestEnvironment : TradeEnvironment -{ - public string TestAddress { get; } - - public TestEnvironment(string name, string url) : base(name) - { - TestAddress = url; - } -} - -// public class TestSocketOptions: SocketExchangeOptions -// { -// public static TestSocketOptions Default = new TestSocketOptions -// { -// Environment = new TestEnvironment("Live", "https://test.test") -// }; - -// /// -// /// ctor -// /// -// public TestSocketOptions() -// { -// Default?.Set(this); -// } - -// public SocketApiOptions SubOptions { get; set; } = new SocketApiOptions(); - -// internal TestSocketOptions Set(TestSocketOptions targetOptions) -// { -// targetOptions = base.Set(targetOptions); -// targetOptions.SubOptions = SubOptions.Set(targetOptions.SubOptions); -// return targetOptions; -// } -// } - -// public class TestSubSocketClient : SocketApiClient -// { -// private MessagePath _channelPath = MessagePath.Get().Property("channel"); -// private MessagePath _actionPath = MessagePath.Get().Property("action"); -// private MessagePath _topicPath = MessagePath.Get().Property("topic"); - -// public Subscription TestSubscription { get; private set; } = null; - -// public override JsonSerializerOptions JsonSerializerOptions => new JsonSerializerOptions(); - -// public TestSubSocketClient(TestSocketOptions options, SocketApiOptions apiOptions) : base(new TraceLogger(), options.Environment.TestAddress, options, apiOptions) -// { - -// } - -// protected internal override IByteMessageAccessor CreateAccessor(WebSocketMessageType type) => new SystemTextJsonByteMessageAccessor(new System.Text.Json.JsonSerializerOptions()); -// protected internal override IMessageSerializer CreateSerializer() => new SystemTextJsonMessageSerializer(new System.Text.Json.JsonSerializerOptions()); - -// /// -// public override string FormatSymbol(string baseAsset, string quoteAsset, TradingMode futuresType, DateTime? deliverDate = null) => $"{baseAsset.ToUpperInvariant()}{quoteAsset.ToUpperInvariant()}"; - -// internal IWebsocket CreateSocketInternal(string address) -// { -// return SocketFactory.CreateWebsocket(_logger, ); -// } - -// protected override AuthenticationProvider CreateAuthenticationProvider(ApiCredentials credentials) -// => new TestAuthProvider(credentials); - -// public CallResult ConnectSocketSub(SocketConnection sub) -// { -// return ConnectSocketAsync(sub, default).Result; -// } - -// public override string GetListenerIdentifier(IMessageAccessor message) -// { -// if (!message.IsValid) -// { -// return "topic"; -// } - -// var id = message.GetValue(_channelPath); -// id ??= message.GetValue(_topicPath); - -// return message.GetValue(_actionPath) + "-" + id; -// } - -// public Task> SubscribeToSomethingAsync(string channel, Action> onUpdate, CancellationToken ct) -// { -// TestSubscription = new TestSubscriptionWithResponseCheck(channel, onUpdate); -// return SubscribeAsync(TestSubscription, ct); -// } - -// public override IMessageConverter CreateMessageConverter() => throw new NotImplementedException(); -// } -//} diff --git a/CryptoExchange.Net/Authentication/ApiCredentials.cs b/CryptoExchange.Net/Authentication/ApiCredentials.cs index 272ad93..ac3f332 100644 --- a/CryptoExchange.Net/Authentication/ApiCredentials.cs +++ b/CryptoExchange.Net/Authentication/ApiCredentials.cs @@ -82,7 +82,7 @@ namespace CryptoExchange.Net.Authentication /// /// Load a key from a file /// - public string ReadFromFile(string path) + public static string ReadFromFile(string path) { using var fileStream = File.OpenRead(path); using var streamReader = new StreamReader(fileStream); diff --git a/CryptoExchange.Net/Clients/SocketApiClient.cs b/CryptoExchange.Net/Clients/SocketApiClient.cs index 31ee886..aea4ff4 100644 --- a/CryptoExchange.Net/Clients/SocketApiClient.cs +++ b/CryptoExchange.Net/Clients/SocketApiClient.cs @@ -884,21 +884,25 @@ namespace CryptoExchange.Net.Clients /// public virtual async Task UnsubscribeAllAsync() { - var sum = _socketConnections.Sum(s => s.Value.UserSubscriptionCount); + var sum = _socketConnections.Sum(s => s.Value.UserSubscriptionCount) + _highPerfSocketConnections.Sum(s => s.Value.UserSubscriptionCount); if (sum == 0) return; - _logger.UnsubscribingAll(_socketConnections.Sum(s => s.Value.UserSubscriptionCount)); + _logger.UnsubscribingAll(sum); var tasks = new List(); + + var socketList = _socketConnections.Values; + foreach (var connection in socketList) { - var socketList = _socketConnections.Values; - foreach (var connection in socketList) - { - foreach(var subscription in connection.Subscriptions.Where(x => x.UserSubscription)) - tasks.Add(connection.CloseAsync(subscription)); - } + foreach(var subscription in connection.Subscriptions.Where(x => x.UserSubscription)) + tasks.Add(connection.CloseAsync(subscription)); } + var highPerfSocketList = _highPerfSocketConnections.Values; + foreach (var connection in highPerfSocketList) + tasks.Add(connection.CloseAsync()); + + await Task.WhenAll(tasks.ToArray()).ConfigureAwait(false); } diff --git a/CryptoExchange.Net/Converters/SystemTextJson/ArrayConverter.cs b/CryptoExchange.Net/Converters/SystemTextJson/ArrayConverter.cs index 51793cb..74f4915 100644 --- a/CryptoExchange.Net/Converters/SystemTextJson/ArrayConverter.cs +++ b/CryptoExchange.Net/Converters/SystemTextJson/ArrayConverter.cs @@ -21,7 +21,6 @@ namespace CryptoExchange.Net.Converters.SystemTextJson public class ArrayConverter : JsonConverter where T : new() #endif { - //private static readonly Lazy> _typePropertyInfo = new Lazy>(CacheTypeAttributes, LazyThreadSafetyMode.PublicationOnly); private static SortedDictionary>? _typePropertyInfo; /// diff --git a/CryptoExchange.Net/Converters/SystemTextJson/DateTimeConverter.cs b/CryptoExchange.Net/Converters/SystemTextJson/DateTimeConverter.cs index 3d3d882..357c02e 100644 --- a/CryptoExchange.Net/Converters/SystemTextJson/DateTimeConverter.cs +++ b/CryptoExchange.Net/Converters/SystemTextJson/DateTimeConverter.cs @@ -56,7 +56,7 @@ namespace CryptoExchange.Net.Converters.SystemTextJson public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options) { - var dtValue = (DateTime)(object)value; + var dtValue = value; if (dtValue == default) writer.WriteStringValue(default(DateTime)); else diff --git a/CryptoExchange.Net/Converters/SystemTextJson/EnumConverter.cs b/CryptoExchange.Net/Converters/SystemTextJson/EnumConverter.cs index 944138b..4f733ba 100644 --- a/CryptoExchange.Net/Converters/SystemTextJson/EnumConverter.cs +++ b/CryptoExchange.Net/Converters/SystemTextJson/EnumConverter.cs @@ -194,7 +194,10 @@ namespace CryptoExchange.Net.Converters.SystemTextJson foreach (var item in _mappingToEnum) { if (item.StringValue.Equals(value, StringComparison.Ordinal)) + { mapping = item; + break; + } } // If not found, try matching ignoring case @@ -203,7 +206,10 @@ namespace CryptoExchange.Net.Converters.SystemTextJson foreach (var item in _mappingToEnum) { if (item.StringValue.Equals(value, StringComparison.OrdinalIgnoreCase)) + { mapping = item; + break; + } } } @@ -310,7 +316,10 @@ namespace CryptoExchange.Net.Converters.SystemTextJson foreach(var item in _mappingToEnum!) { if (item.StringValue.Equals(value, StringComparison.Ordinal)) + { mapping = item; + break; + } } // If not found, try matching ignoring case @@ -319,7 +328,10 @@ namespace CryptoExchange.Net.Converters.SystemTextJson foreach (var item in _mappingToEnum) { if (item.StringValue.Equals(value, StringComparison.OrdinalIgnoreCase)) + { mapping = item; + break; + } } }