diff --git a/CryptoExchange.Net/BaseClient.cs b/CryptoExchange.Net/BaseClient.cs index 3af741d..7460bb5 100644 --- a/CryptoExchange.Net/BaseClient.cs +++ b/CryptoExchange.Net/BaseClient.cs @@ -1,16 +1,12 @@ -using CryptoExchange.Net.Attributes; -using CryptoExchange.Net.Authentication; +using CryptoExchange.Net.Authentication; using CryptoExchange.Net.Logging; using CryptoExchange.Net.Objects; using Microsoft.Extensions.Logging; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System; -using System.Collections.Generic; using System.Globalization; using System.IO; -using System.Linq; -using System.Reflection; using System.Text; using System.Threading.Tasks; @@ -152,8 +148,7 @@ namespace CryptoExchange.Net /// protected CallResult Deserialize(JToken obj, JsonSerializer? serializer = null, int? requestId = null) { - if (serializer == null) - serializer = defaultSerializer; + serializer ??= defaultSerializer; try { @@ -191,8 +186,7 @@ namespace CryptoExchange.Net /// protected async Task> DeserializeAsync(Stream stream, JsonSerializer? serializer = null, int? requestId = null, long? elapsedMilliseconds = null) { - if (serializer == null) - serializer = defaultSerializer; + serializer ??= defaultSerializer; try { diff --git a/CryptoExchange.Net/Converters/ArrayConverter.cs b/CryptoExchange.Net/Converters/ArrayConverter.cs index b196fd0..26a17bd 100644 --- a/CryptoExchange.Net/Converters/ArrayConverter.cs +++ b/CryptoExchange.Net/Converters/ArrayConverter.cs @@ -36,7 +36,7 @@ namespace CryptoExchange.Net.Converters return ParseObject(arr, result, objectType); } - private static object? ParseObject(JArray arr, object result, Type objectType) + private static object ParseObject(JArray arr, object result, Type objectType) { foreach (var property in objectType.GetProperties()) { @@ -63,8 +63,8 @@ namespace CryptoExchange.Net.Converters var arrayResult = (IList)Activator.CreateInstance(property.PropertyType, new [] { innerArray.Count }); foreach (var obj in innerArray) { - var innerObj = Activator.CreateInstance(objType); - arrayResult[count] = ParseObject((JArray)obj, innerObj, objType); + var innerObj = Activator.CreateInstance(objType!); + arrayResult[count] = ParseObject((JArray)obj, innerObj, objType!); count++; } property.SetValue(result, arrayResult); @@ -72,8 +72,8 @@ namespace CryptoExchange.Net.Converters else { var arrayResult = (IList)Activator.CreateInstance(property.PropertyType, new [] { 1 }); - var innerObj = Activator.CreateInstance(objType); - arrayResult[0] = ParseObject(innerArray, innerObj, objType); + var innerObj = Activator.CreateInstance(objType!); + arrayResult[0] = ParseObject(innerArray, innerObj, objType!); property.SetValue(result, arrayResult); } continue; diff --git a/CryptoExchange.Net/ExtensionMethods.cs b/CryptoExchange.Net/ExtensionMethods.cs index 2055978..2a19126 100644 --- a/CryptoExchange.Net/ExtensionMethods.cs +++ b/CryptoExchange.Net/ExtensionMethods.cs @@ -5,8 +5,6 @@ using System.Linq; using System.Runtime.InteropServices; using System.Security; using System.Text; -using System.Threading; -using System.Threading.Tasks; using CryptoExchange.Net.Logging; using CryptoExchange.Net.Objects; using Microsoft.Extensions.Logging; @@ -333,7 +331,7 @@ namespace CryptoExchange.Net /// /// /// - public static string ToLogString(this Exception exception) + public static string ToLogString(this Exception? exception) { var message = new StringBuilder(); var indent = 0; diff --git a/CryptoExchange.Net/Interfaces/IRateLimiter.cs b/CryptoExchange.Net/Interfaces/IRateLimiter.cs index f5b3361..5b6f830 100644 --- a/CryptoExchange.Net/Interfaces/IRateLimiter.cs +++ b/CryptoExchange.Net/Interfaces/IRateLimiter.cs @@ -1,6 +1,5 @@ using CryptoExchange.Net.Logging; using CryptoExchange.Net.Objects; -using System; using System.Net.Http; using System.Security; using System.Threading; diff --git a/CryptoExchange.Net/Interfaces/IRestClient.cs b/CryptoExchange.Net/Interfaces/IRestClient.cs index 015c6f5..e235f62 100644 --- a/CryptoExchange.Net/Interfaces/IRestClient.cs +++ b/CryptoExchange.Net/Interfaces/IRestClient.cs @@ -1,7 +1,4 @@ using System; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; using CryptoExchange.Net.Objects; namespace CryptoExchange.Net.Interfaces @@ -21,17 +18,6 @@ namespace CryptoExchange.Net.Interfaces /// int TotalRequestsMade { get; } - /// - /// Adds a rate limiter to the client. There are 2 choices, the and the . - /// - /// The limiter to add - void AddRateLimiter(IRateLimiter limiter); - - /// - /// Removes all rate limiters from this client - /// - void RemoveRateLimiters(); - /// /// The options provided for this client /// diff --git a/CryptoExchange.Net/Objects/AsyncAutoResetEvent.cs b/CryptoExchange.Net/Objects/AsyncAutoResetEvent.cs index 2daddd7..e6ac1d9 100644 --- a/CryptoExchange.Net/Objects/AsyncAutoResetEvent.cs +++ b/CryptoExchange.Net/Objects/AsyncAutoResetEvent.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Threading; using System.Threading.Tasks; @@ -12,10 +11,10 @@ namespace CryptoExchange.Net.Objects /// public class AsyncResetEvent : IDisposable { - private readonly static Task _completed = Task.FromResult(true); + private static readonly Task _completed = Task.FromResult(true); private readonly Queue> _waits = new Queue>(); private bool _signaled; - private bool _reset; + private readonly bool _reset; /// /// New AsyncResetEvent diff --git a/CryptoExchange.Net/Objects/RateLimiter.cs b/CryptoExchange.Net/Objects/RateLimiter.cs index 420f413..dc0b4e8 100644 --- a/CryptoExchange.Net/Objects/RateLimiter.cs +++ b/CryptoExchange.Net/Objects/RateLimiter.cs @@ -1,6 +1,5 @@ using CryptoExchange.Net.Interfaces; using CryptoExchange.Net.Logging; -using CryptoExchange.Net.Objects; using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; @@ -106,7 +105,7 @@ namespace CryptoExchange.Net.Objects { int totalWaitTime = 0; - EndpointRateLimiter endpointLimit; + EndpointRateLimiter? endpointLimit; lock (_limiterLock) endpointLimit = Limiters.OfType().SingleOrDefault(h => h.Endpoints.Contains(endpoint) && (h.Method == null || h.Method == method)); if(endpointLimit != null) @@ -128,7 +127,7 @@ namespace CryptoExchange.Net.Objects { if (partialEndpointLimit.CountPerEndpoint) { - SingleTopicRateLimiter thisEndpointLimit; + SingleTopicRateLimiter? thisEndpointLimit; lock (_limiterLock) { thisEndpointLimit = Limiters.OfType().SingleOrDefault(h => h.Type == RateLimitType.PartialEndpoint && (string)h.Topic == endpoint); @@ -158,7 +157,7 @@ namespace CryptoExchange.Net.Objects if(partialEndpointLimits.Any(p => p.IgnoreOtherRateLimits)) return new CallResult(totalWaitTime, null); - ApiKeyRateLimiter apiLimit; + ApiKeyRateLimiter? apiLimit; lock (_limiterLock) apiLimit = Limiters.OfType().SingleOrDefault(h => h.Type == RateLimitType.ApiKey); if (apiLimit != null) @@ -176,7 +175,7 @@ namespace CryptoExchange.Net.Objects } else if (signed || !apiLimit.OnlyForSignedRequests) { - SingleTopicRateLimiter thisApiLimit; + SingleTopicRateLimiter? thisApiLimit; lock (_limiterLock) { thisApiLimit = Limiters.OfType().SingleOrDefault(h => h.Type == RateLimitType.ApiKey && ((SecureString)h.Topic).IsEqualTo(apiKey)); @@ -198,7 +197,7 @@ namespace CryptoExchange.Net.Objects if ((signed || apiLimit?.OnlyForSignedRequests == false) && apiLimit?.IgnoreTotalRateLimit == true) return new CallResult(totalWaitTime, null); - TotalRateLimiter totalLimit; + TotalRateLimiter? totalLimit; lock (_limiterLock) totalLimit = Limiters.OfType().SingleOrDefault(); if (totalLimit != null) diff --git a/CryptoExchange.Net/OrderBook/SymbolOrderBook.cs b/CryptoExchange.Net/OrderBook/SymbolOrderBook.cs index a7f1e29..1a10689 100644 --- a/CryptoExchange.Net/OrderBook/SymbolOrderBook.cs +++ b/CryptoExchange.Net/OrderBook/SymbolOrderBook.cs @@ -18,22 +18,24 @@ namespace CryptoExchange.Net.OrderBook /// public abstract class SymbolOrderBook : ISymbolOrderBook, IDisposable { - private readonly object bookLock = new object(); + private readonly object _bookLock = new object(); - private OrderBookStatus status; - private UpdateSubscription? subscription; + private OrderBookStatus _status; + private UpdateSubscription? _subscription; private bool _stopProcessing; private Task? _processTask; private readonly AutoResetEvent _queueEvent; private readonly ConcurrentQueue _processQueue; - private readonly bool validateChecksum; + private readonly bool _validateChecksum; private class EmptySymbolOrderBookEntry : ISymbolOrderBookEntry { - public decimal Quantity { get { return 0m; } set {; } } - public decimal Price { get { return 0m; } set {; } } + public decimal Quantity { get => 0m; + set { } } + public decimal Price { get => 0m; + set { } } } private static readonly ISymbolOrderBookEntry emptySymbolOrderBookEntry = new EmptySymbolOrderBookEntry(); @@ -90,16 +92,16 @@ namespace CryptoExchange.Net.OrderBook /// public OrderBookStatus Status { - get => status; + get => _status; set { - if (value == status) + if (value == _status) return; - var old = status; - status = value; + var old = _status; + _status = value; log.Write(LogLevel.Information, $"{Id} order book {Symbol} status changed: {old} => {value}"); - OnStatusChange?.Invoke(old, status); + OnStatusChange?.Invoke(old, _status); } } @@ -132,7 +134,7 @@ namespace CryptoExchange.Net.OrderBook { get { - lock (bookLock) + lock (_bookLock) return asks.Select(a => a.Value).ToList(); } } @@ -142,7 +144,7 @@ namespace CryptoExchange.Net.OrderBook { get { - lock (bookLock) + lock (_bookLock) return bids.Select(a => a.Value).ToList(); } } @@ -152,7 +154,7 @@ namespace CryptoExchange.Net.OrderBook { get { - lock (bookLock) + lock (_bookLock) return (Bids, Asks); } } @@ -162,7 +164,7 @@ namespace CryptoExchange.Net.OrderBook { get { - lock (bookLock) + lock (_bookLock) return bids.FirstOrDefault().Value ?? emptySymbolOrderBookEntry; } } @@ -172,7 +174,7 @@ namespace CryptoExchange.Net.OrderBook { get { - lock (bookLock) + lock (_bookLock) return asks.FirstOrDefault().Value ?? emptySymbolOrderBookEntry; } } @@ -180,7 +182,7 @@ namespace CryptoExchange.Net.OrderBook /// public (ISymbolOrderBookEntry Bid, ISymbolOrderBookEntry Ask) BestOffers { get { - lock (bookLock) + lock (_bookLock) return (BestBid,BestAsk); } } @@ -204,7 +206,7 @@ namespace CryptoExchange.Net.OrderBook _processQueue = new ConcurrentQueue(); _queueEvent = new AutoResetEvent(false); - validateChecksum = options.ChecksumValidationEnabled; + _validateChecksum = options.ChecksumValidationEnabled; Symbol = symbol; Status = OrderBookStatus.Disconnected; @@ -233,21 +235,21 @@ namespace CryptoExchange.Net.OrderBook return new CallResult(false, startResult.Error); } - subscription = startResult.Data; - subscription.ConnectionLost += () => + _subscription = startResult.Data; + _subscription.ConnectionLost += () => { log.Write(LogLevel.Warning, $"{Id} order book {Symbol} connection lost"); Status = OrderBookStatus.Reconnecting; Reset(); }; - subscription.ConnectionClosed += () => + _subscription.ConnectionClosed += () => { log.Write(LogLevel.Warning, $"{Id} order book {Symbol} disconnected"); Status = OrderBookStatus.Disconnected; _ = StopAsync(); }; - subscription.ConnectionRestored += async time => await ResyncAsync().ConfigureAwait(false); + _subscription.ConnectionRestored += async time => await ResyncAsync().ConfigureAwait(false); Status = OrderBookStatus.Synced; return new CallResult(true, null); } @@ -261,8 +263,8 @@ namespace CryptoExchange.Net.OrderBook if (_processTask != null) await _processTask.ConfigureAwait(false); - if (subscription != null) - await subscription.CloseAsync().ConfigureAwait(false); + if (_subscription != null) + await _subscription.CloseAsync().ConfigureAwait(false); log.Write(LogLevel.Debug, $"{Id} order book {Symbol} stopped"); } @@ -275,7 +277,7 @@ namespace CryptoExchange.Net.OrderBook var totalCost = 0m; var totalAmount = 0m; var amountLeft = quantity; - lock (bookLock) + lock (_bookLock) { var list = type == OrderBookEntryType.Ask ? asks : bids; @@ -283,7 +285,7 @@ namespace CryptoExchange.Net.OrderBook while (amountLeft > 0) { if (step == list.Count) - return new CallResult(0, new InvalidOperationError($"Quantity is larger than order in the order book")); + return new CallResult(0, new InvalidOperationError("Quantity is larger than order in the order book")); var element = list.ElementAt(step); var stepAmount = Math.Min(element.Value.Quantity, amountLeft); @@ -550,7 +552,7 @@ namespace CryptoExchange.Net.OrderBook if (_stopProcessing) { - log.Write(LogLevel.Trace, $"Skipping message because of resubscribing"); + log.Write(LogLevel.Trace, "Skipping message because of resubscribing"); continue; } @@ -566,7 +568,7 @@ namespace CryptoExchange.Net.OrderBook private void ProcessInitialOrderBookItem(InitialOrderBookItem item) { - lock (bookLock) + lock (_bookLock) { bookSet = true; asks.Clear(); @@ -591,7 +593,7 @@ namespace CryptoExchange.Net.OrderBook private void ProcessQueueItem(ProcessQueueItem item) { - lock (bookLock) + lock (_bookLock) { if (!bookSet) { @@ -629,9 +631,9 @@ namespace CryptoExchange.Net.OrderBook private void ProcessChecksum(ChecksumItem ci) { - lock (bookLock) + lock (_bookLock) { - if (!validateChecksum) + if (!_validateChecksum) return; bool checksumResult = false; @@ -652,7 +654,6 @@ namespace CryptoExchange.Net.OrderBook log.Write(LogLevel.Warning, $"{Id} order book {Symbol} out of sync. Resyncing"); _stopProcessing = true; Resubscribe(); - return; } } } @@ -662,15 +663,15 @@ namespace CryptoExchange.Net.OrderBook Status = OrderBookStatus.Syncing; _ = Task.Run(async () => { - await subscription!.UnsubscribeAsync().ConfigureAwait(false); + await _subscription!.UnsubscribeAsync().ConfigureAwait(false); Reset(); _stopProcessing = false; - if (!await subscription!.ResubscribeAsync().ConfigureAwait(false)) + if (!await _subscription!.ResubscribeAsync().ConfigureAwait(false)) { // Resubscribing failed, reconnect the socket log.Write(LogLevel.Warning, $"{Id} order book {Symbol} resync failed, reconnecting socket"); Status = OrderBookStatus.Reconnecting; - _ = subscription!.ReconnectAsync(); + _ = _subscription!.ReconnectAsync(); } else await ResyncAsync().ConfigureAwait(false); diff --git a/CryptoExchange.Net/RestClient.cs b/CryptoExchange.Net/RestClient.cs index 68e06c7..62cdc55 100644 --- a/CryptoExchange.Net/RestClient.cs +++ b/CryptoExchange.Net/RestClient.cs @@ -5,8 +5,6 @@ using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Net.Http; -using System.Net.NetworkInformation; -using System.Net.Sockets; using System.Threading; using System.Threading.Tasks; using System.Web; @@ -64,7 +62,7 @@ namespace CryptoExchange.Net /// /// List of rate limiters /// - protected IEnumerable RateLimiters { get; private set; } + protected IEnumerable RateLimiters { get; } /// public int TotalRequestsMade { get; private set; } @@ -99,28 +97,6 @@ namespace CryptoExchange.Net RateLimiters = rateLimiters; } - /// - /// Adds a rate limiter to the client. There are 2 choices, the and the . - /// - /// The limiter to add - public void AddRateLimiter(IRateLimiter limiter) - { - if (limiter == null) - throw new ArgumentNullException(nameof(limiter)); - - var rateLimiters = RateLimiters.ToList(); - rateLimiters.Add(limiter); - RateLimiters = rateLimiters; - } - - /// - /// Removes all rate limiters from this client - /// - public void RemoveRateLimiters() - { - RateLimiters = new List(); - } - /// /// Execute a request to the uri and deserialize the response into the provided type parameter /// @@ -308,8 +284,7 @@ namespace CryptoExchange.Net int requestId, Dictionary? additionalHeaders) { - if (parameters == null) - parameters = new Dictionary(); + parameters ??= new Dictionary(); var uriString = uri.ToString(); if (authProvider != null) diff --git a/CryptoExchange.Net/SocketClient.cs b/CryptoExchange.Net/SocketClient.cs index 7022bd3..0f4ad84 100644 --- a/CryptoExchange.Net/SocketClient.cs +++ b/CryptoExchange.Net/SocketClient.cs @@ -157,7 +157,15 @@ namespace CryptoExchange.Net var released = false; // Wait for a semaphore here, so we only connect 1 socket at a time. // This is necessary for being able to see if connections can be combined - await semaphoreSlim.WaitAsync().ConfigureAwait(false); + try + { + await semaphoreSlim.WaitAsync(ct).ConfigureAwait(false); + } + catch (OperationCanceledException) + { + return new CallResult(null, new CancellationRequestedError()); + } + try { // Get a new or existing socket connection diff --git a/CryptoExchange.Net/Sockets/CryptoExchangeWebSocketClient.cs b/CryptoExchange.Net/Sockets/CryptoExchangeWebSocketClient.cs index bc74c74..e0166ff 100644 --- a/CryptoExchange.Net/Sockets/CryptoExchangeWebSocketClient.cs +++ b/CryptoExchange.Net/Sockets/CryptoExchangeWebSocketClient.cs @@ -142,7 +142,7 @@ namespace CryptoExchange.Net.Sockets if (!_receivedMessages.Any()) return 0; - return Math.Round(_receivedMessages.Sum(v => v.Bytes) / 1000 / 3d); + return Math.Round(_receivedMessages.Sum(v => v.Bytes) / 1000d / 3d); } } } @@ -371,8 +371,7 @@ namespace CryptoExchange.Net.Sockets DateTime? start = null; while (MessagesSentLastSecond() >= RatelimitPerSecond) { - if (start == null) - start = DateTime.UtcNow; + start ??= DateTime.UtcNow; await Task.Delay(10).ConfigureAwait(false); } @@ -479,8 +478,7 @@ namespace CryptoExchange.Net.Sockets { // We received data, but it is not complete, write it to a memory stream for reassembling multiPartMessage = true; - if (memoryStream == null) - memoryStream = new MemoryStream(); + memoryStream ??= new MemoryStream(); log.Write(LogLevel.Trace, $"Socket {Id} received {receiveResult.Count} bytes in partial message"); await memoryStream.WriteAsync(buffer.Array, buffer.Offset, receiveResult.Count).ConfigureAwait(false); } @@ -490,7 +488,7 @@ namespace CryptoExchange.Net.Sockets { // Received a complete message and it's not multi part log.Write(LogLevel.Trace, $"Socket {Id} received {receiveResult.Count} bytes in single message"); - HandleMessage(buffer.Array, buffer.Offset, receiveResult.Count, receiveResult.MessageType); + HandleMessage(buffer.Array!, buffer.Offset, receiveResult.Count, receiveResult.MessageType); } else { @@ -586,7 +584,6 @@ namespace CryptoExchange.Net.Sockets catch(Exception e) { log.Write(LogLevel.Error, $"Socket {Id} unhandled exception during message processing: " + e.ToLogString()); - return; } } diff --git a/CryptoExchange.Net/Sockets/SocketConnection.cs b/CryptoExchange.Net/Sockets/SocketConnection.cs index 829a2b5..2332554 100644 --- a/CryptoExchange.Net/Sockets/SocketConnection.cs +++ b/CryptoExchange.Net/Sockets/SocketConnection.cs @@ -562,7 +562,7 @@ namespace CryptoExchange.Net.Sockets if (subscription.Confirmed) await socketClient.UnsubscribeAsync(this, subscription).ConfigureAwait(false); - var shouldCloseConnection = false; + bool shouldCloseConnection; lock (subscriptionLock) shouldCloseConnection = !subscriptions.Any(r => r.UserSubscription && subscription != r);