diff --git a/CryptoExchange.Net/Authentication/ApiCredentials.cs b/CryptoExchange.Net/Authentication/ApiCredentials.cs index 6b2d56a..e6f1dcb 100644 --- a/CryptoExchange.Net/Authentication/ApiCredentials.cs +++ b/CryptoExchange.Net/Authentication/ApiCredentials.cs @@ -14,12 +14,12 @@ namespace CryptoExchange.Net.Authentication /// /// The api key to authenticate requests /// - public SecureString Key { get; private set; } + public SecureString Key { get; } /// /// The api secret to authenticate requests /// - public SecureString Secret { get; private set; } + public SecureString Secret { get; } /// /// The private key to authenticate requests diff --git a/CryptoExchange.Net/BaseClient.cs b/CryptoExchange.Net/BaseClient.cs index 6d48158..b4e79ed 100644 --- a/CryptoExchange.Net/BaseClient.cs +++ b/CryptoExchange.Net/BaseClient.cs @@ -140,7 +140,7 @@ namespace CryptoExchange.Net protected CallResult Deserialize(string data, bool checkObject = true, JsonSerializer serializer = null) { var tokenResult = ValidateJson(data); - return !tokenResult.Success ? new CallResult(default(T), tokenResult.Error) : Deserialize(tokenResult.Data, checkObject, serializer); + return !tokenResult.Success ? new CallResult(default, tokenResult.Error) : Deserialize(tokenResult.Data, checkObject, serializer); } /// @@ -184,19 +184,19 @@ namespace CryptoExchange.Net { var info = $"Deserialize JsonReaderException: {jre.Message}, Path: {jre.Path}, LineNumber: {jre.LineNumber}, LinePosition: {jre.LinePosition}. Received data: {obj}"; log.Write(LogVerbosity.Error, info); - return new CallResult(default(T), new DeserializeError(info)); + return new CallResult(default, new DeserializeError(info)); } catch (JsonSerializationException jse) { var info = $"Deserialize JsonSerializationException: {jse.Message}. Received data: {obj}"; log.Write(LogVerbosity.Error, info); - return new CallResult(default(T), new DeserializeError(info)); + return new CallResult(default, new DeserializeError(info)); } catch (Exception ex) { var info = $"Deserialize Unknown Exception: {ex.Message}. Received data: {obj}"; log.Write(LogVerbosity.Error, info); - return new CallResult(default(T), new DeserializeError(info)); + return new CallResult(default, new DeserializeError(info)); } } @@ -277,7 +277,7 @@ namespace CryptoExchange.Net var attr = prop.GetCustomAttributes(typeof(JsonPropertyAttribute), false).FirstOrDefault(); if (attr == null) { - if (String.Equals(prop.Name, name, StringComparison.CurrentCultureIgnoreCase)) + if (string.Equals(prop.Name, name, StringComparison.CurrentCultureIgnoreCase)) return prop; } else diff --git a/CryptoExchange.Net/Converters/ArrayConverter.cs b/CryptoExchange.Net/Converters/ArrayConverter.cs index 6a8d5e1..ce6dede 100644 --- a/CryptoExchange.Net/Converters/ArrayConverter.cs +++ b/CryptoExchange.Net/Converters/ArrayConverter.cs @@ -76,7 +76,7 @@ namespace CryptoExchange.Net.Converters var converterAttribute = (JsonConverterAttribute)property.GetCustomAttribute(typeof(JsonConverterAttribute)) ?? (JsonConverterAttribute)property.PropertyType.GetCustomAttribute(typeof(JsonConverterAttribute)); var conversionAttribute = (JsonConversionAttribute)property.GetCustomAttribute(typeof(JsonConversionAttribute)) ?? (JsonConversionAttribute)property.PropertyType.GetCustomAttribute(typeof(JsonConversionAttribute)); - object value = null; + object value; if (converterAttribute != null) { value = arr[attribute.Index].ToObject(property.PropertyType, new JsonSerializer {Converters = {(JsonConverter) Activator.CreateInstance(converterAttribute.ConverterType)}}); diff --git a/CryptoExchange.Net/Converters/BaseConverter.cs b/CryptoExchange.Net/Converters/BaseConverter.cs index 47ce489..b458149 100644 --- a/CryptoExchange.Net/Converters/BaseConverter.cs +++ b/CryptoExchange.Net/Converters/BaseConverter.cs @@ -78,7 +78,7 @@ namespace CryptoExchange.Net.Converters return true; } - result = default(T); + result = default; return false; } diff --git a/CryptoExchange.Net/Converters/TimestampNanoSecondsConverter.cs b/CryptoExchange.Net/Converters/TimestampNanoSecondsConverter.cs index 17a6803..fb8205d 100644 --- a/CryptoExchange.Net/Converters/TimestampNanoSecondsConverter.cs +++ b/CryptoExchange.Net/Converters/TimestampNanoSecondsConverter.cs @@ -8,6 +8,8 @@ namespace CryptoExchange.Net.Converters /// public class TimestampNanoSecondsConverter : JsonConverter { + private const decimal ticksPerNanosecond = TimeSpan.TicksPerMillisecond / 1000m / 1000; + /// public override bool CanConvert(Type objectType) { @@ -20,7 +22,6 @@ namespace CryptoExchange.Net.Converters if (reader.Value == null) return null; - var ticksPerNanosecond = (TimeSpan.TicksPerMillisecond / 1000m / 1000); var nanoSeconds = long.Parse(reader.Value.ToString()); return new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddTicks((long)Math.Round(nanoSeconds * ticksPerNanosecond)); } @@ -28,7 +29,6 @@ namespace CryptoExchange.Net.Converters /// public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { - var ticksPerNanosecond = (TimeSpan.TicksPerMillisecond / 1000m / 1000); writer.WriteValue((long)Math.Round(((DateTime)value - new DateTime(1970, 1, 1)).Ticks / ticksPerNanosecond)); } } diff --git a/CryptoExchange.Net/CryptoExchange.Net.xml b/CryptoExchange.Net/CryptoExchange.Net.xml index 0a2f54e..482e013 100644 --- a/CryptoExchange.Net/CryptoExchange.Net.xml +++ b/CryptoExchange.Net/CryptoExchange.Net.xml @@ -469,7 +469,7 @@ - Header collection to inenumerable + Header collection to IEnumerable @@ -709,6 +709,110 @@ + + + Interface for order book + + + + + The status of the order book. Order book is up to date when the status is `Synced` + + + + + Last update identifier + + + + + The symbol of the order book + + + + + Event when the state changes + + + + + Event when order book was updated. Be careful! It can generate a lot of events at high-liquidity markets + + + + + Timestamp of the last update + + + + + The number of asks in the book + + + + + The number of bids in the book + + + + + The list of asks + + + + + The list of bids + + + + + The best bid currently in the order book + + + + + The best ask currently in the order book + + + + + Start connecting and synchronizing the order book + + + + + + Start connecting and synchronizing the order book + + + + + + Stop syncing the order book + + + + + + Stop syncing the order book + + + + + + Interface for order book entries + + + + + The quantity of the entry + + + + + The price of the entry + + Interface for websocket interaction @@ -1445,21 +1549,6 @@ - - - Interface for order book entries - - - - - The quantity of the entry - - - - - The price of the entry - - Order book entry @@ -1522,7 +1611,7 @@ The type - + ctor @@ -1576,12 +1665,12 @@ - Event when orderbook was updated. Be careful! It can generate a lot of events at high-liquidity markets + Event when order book was updated. Be careful! It can generate a lot of events at high-liquidity markets - + - Should be useful for low-liquidity order-books to monitor market activity + Timestamp of the last update @@ -1662,7 +1751,7 @@ - + Set the initial data for the order book @@ -1683,7 +1772,7 @@ Check and empty the process buffer; see what entries to update the book with - + Update order book with an entry @@ -1789,7 +1878,7 @@ - Create request object for webrequest + Create request object for web request @@ -2126,7 +2215,7 @@ Query for data - Exepected result type + Expected result type The request to send Whether the socket should be authenticated diff --git a/CryptoExchange.Net/ExtensionMethods.cs b/CryptoExchange.Net/ExtensionMethods.cs index cd80a5c..8d2d2c2 100644 --- a/CryptoExchange.Net/ExtensionMethods.cs +++ b/CryptoExchange.Net/ExtensionMethods.cs @@ -127,7 +127,7 @@ namespace CryptoExchange.Net } /// - /// Header collection to inenumerable + /// Header collection to IEnumerable /// /// /// @@ -153,7 +153,7 @@ namespace CryptoExchange.Net public static async Task WaitOneAsync(this WaitHandle handle, int millisecondsTimeout, CancellationToken cancellationToken) { RegisteredWaitHandle registeredHandle = null; - CancellationTokenRegistration tokenRegistration = default(CancellationTokenRegistration); + CancellationTokenRegistration tokenRegistration = default; try { var tcs = new TaskCompletionSource(); diff --git a/CryptoExchange.Net/Interfaces/IRestClient.cs b/CryptoExchange.Net/Interfaces/IRestClient.cs index b3a8c4b..c2f3b82 100644 --- a/CryptoExchange.Net/Interfaces/IRestClient.cs +++ b/CryptoExchange.Net/Interfaces/IRestClient.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; -using CryptoExchange.Net.Interfaces; using CryptoExchange.Net.Objects; using CryptoExchange.Net.RateLimiter; diff --git a/CryptoExchange.Net/Interfaces/ISymbolOrderBook.cs b/CryptoExchange.Net/Interfaces/ISymbolOrderBook.cs new file mode 100644 index 0000000..ad09904 --- /dev/null +++ b/CryptoExchange.Net/Interfaces/ISymbolOrderBook.cs @@ -0,0 +1,93 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using CryptoExchange.Net.Objects; + +namespace CryptoExchange.Net.Interfaces +{ + /// + /// Interface for order book + /// + public interface ISymbolOrderBook + { + /// + /// The status of the order book. Order book is up to date when the status is `Synced` + /// + OrderBookStatus Status { get; set; } + + /// + /// Last update identifier + /// + long LastSequenceNumber { get; } + /// + /// The symbol of the order book + /// + string Symbol { get; } + + /// + /// Event when the state changes + /// + event Action OnStatusChange; + /// + /// Event when order book was updated. Be careful! It can generate a lot of events at high-liquidity markets + /// + event Action OnOrderBookUpdate; + /// + /// Timestamp of the last update + /// + DateTime LastOrderBookUpdate { get; } + + /// + /// The number of asks in the book + /// + int AskCount { get; } + /// + /// The number of bids in the book + /// + int BidCount { get; } + + /// + /// The list of asks + /// + IEnumerable Asks { get; } + + /// + /// The list of bids + /// + IEnumerable Bids { get; } + + /// + /// The best bid currently in the order book + /// + ISymbolOrderBookEntry BestBid { get; } + + /// + /// The best ask currently in the order book + /// + ISymbolOrderBookEntry BestAsk { get; } + + /// + /// Start connecting and synchronizing the order book + /// + /// + CallResult Start(); + + /// + /// Start connecting and synchronizing the order book + /// + /// + Task> StartAsync(); + + /// + /// Stop syncing the order book + /// + /// + void Stop(); + + /// + /// Stop syncing the order book + /// + /// + Task StopAsync(); + } +} diff --git a/CryptoExchange.Net/OrderBook/ISymbolOrderBookEntry.cs b/CryptoExchange.Net/Interfaces/ISymbolOrderBookEntry.cs similarity index 89% rename from CryptoExchange.Net/OrderBook/ISymbolOrderBookEntry.cs rename to CryptoExchange.Net/Interfaces/ISymbolOrderBookEntry.cs index b5cb8ce..419f41a 100644 --- a/CryptoExchange.Net/OrderBook/ISymbolOrderBookEntry.cs +++ b/CryptoExchange.Net/Interfaces/ISymbolOrderBookEntry.cs @@ -1,4 +1,4 @@ -namespace CryptoExchange.Net.OrderBook +namespace CryptoExchange.Net.Interfaces { /// /// Interface for order book entries diff --git a/CryptoExchange.Net/Objects/ByteOrderComparer.cs b/CryptoExchange.Net/Objects/ByteOrderComparer.cs index 29be971..7ad3cbd 100644 --- a/CryptoExchange.Net/Objects/ByteOrderComparer.cs +++ b/CryptoExchange.Net/Objects/ByteOrderComparer.cs @@ -21,8 +21,8 @@ namespace CryptoExchange.Net.Objects // If one is null and the other isn't, then the // one that is null is "lesser". - if (x == null && y != null) return -1; - if (x != null && y == null) return 1; + if (x == null) return -1; + if (y == null) return 1; // Both arrays are non-null. Find the shorter // of the two lengths. diff --git a/CryptoExchange.Net/Objects/CallResult.cs b/CryptoExchange.Net/Objects/CallResult.cs index d8c2f59..1085328 100644 --- a/CryptoExchange.Net/Objects/CallResult.cs +++ b/CryptoExchange.Net/Objects/CallResult.cs @@ -71,7 +71,7 @@ namespace CryptoExchange.Net.Objects /// public static WebCallResult CreateErrorResult(Error error) { - return new WebCallResult(null, null, default(T), error); + return new WebCallResult(null, null, default, error); } /// @@ -83,7 +83,7 @@ namespace CryptoExchange.Net.Objects /// public static WebCallResult CreateErrorResult(HttpStatusCode? code, IEnumerable> responseHeaders, Error error) { - return new WebCallResult(code, responseHeaders, default(T), error); + return new WebCallResult(code, responseHeaders, default, error); } } } diff --git a/CryptoExchange.Net/Objects/Enums.cs b/CryptoExchange.Net/Objects/Enums.cs index 90c06ed..3af3694 100644 --- a/CryptoExchange.Net/Objects/Enums.cs +++ b/CryptoExchange.Net/Objects/Enums.cs @@ -65,7 +65,7 @@ /// /// Data synced, order book is up to date /// - Synced, + Synced } /// diff --git a/CryptoExchange.Net/OrderBook/OrderBookEntry.cs b/CryptoExchange.Net/OrderBook/OrderBookEntry.cs index 3faccf2..4bf9c39 100644 --- a/CryptoExchange.Net/OrderBook/OrderBookEntry.cs +++ b/CryptoExchange.Net/OrderBook/OrderBookEntry.cs @@ -1,4 +1,6 @@ -namespace CryptoExchange.Net.OrderBook +using CryptoExchange.Net.Interfaces; + +namespace CryptoExchange.Net.OrderBook { /// /// Order book entry diff --git a/CryptoExchange.Net/OrderBook/ProcessEntry.cs b/CryptoExchange.Net/OrderBook/ProcessEntry.cs index a59bc5f..5ebff10 100644 --- a/CryptoExchange.Net/OrderBook/ProcessEntry.cs +++ b/CryptoExchange.Net/OrderBook/ProcessEntry.cs @@ -1,4 +1,5 @@ -using CryptoExchange.Net.Objects; +using CryptoExchange.Net.Interfaces; +using CryptoExchange.Net.Objects; namespace CryptoExchange.Net.OrderBook { diff --git a/CryptoExchange.Net/OrderBook/SymbolOrderBook.cs b/CryptoExchange.Net/OrderBook/SymbolOrderBook.cs index d942ed9..47671b2 100644 --- a/CryptoExchange.Net/OrderBook/SymbolOrderBook.cs +++ b/CryptoExchange.Net/OrderBook/SymbolOrderBook.cs @@ -4,6 +4,7 @@ using System.Globalization; using System.IO; using System.Linq; using System.Threading.Tasks; +using CryptoExchange.Net.Interfaces; using CryptoExchange.Net.Logging; using CryptoExchange.Net.Objects; using CryptoExchange.Net.Sockets; @@ -13,7 +14,7 @@ namespace CryptoExchange.Net.OrderBook /// /// Base for order book implementations /// - public abstract class SymbolOrderBook : IDisposable + public abstract class SymbolOrderBook : ISymbolOrderBook, IDisposable { /// /// The process buffer, used while syncing @@ -23,12 +24,12 @@ namespace CryptoExchange.Net.OrderBook /// /// The ask list /// - protected SortedList asks; + protected SortedList asks; /// /// The bid list /// - protected SortedList bids; + protected SortedList bids; private OrderBookStatus status; private UpdateSubscription subscription; private readonly bool sequencesAreConsecutive; @@ -72,13 +73,13 @@ namespace CryptoExchange.Net.OrderBook /// public event Action OnStatusChange; /// - /// Event when orderbook was updated. Be careful! It can generate a lot of events at high-liquidity markets + /// Event when order book was updated. Be careful! It can generate a lot of events at high-liquidity markets /// public event Action OnOrderBookUpdate; /// - /// Should be useful for low-liquidity order-books to monitor market activity + /// Timestamp of the last update /// - public DateTime LastOrderBookUpdate; + public DateTime LastOrderBookUpdate { get; private set; } /// /// The number of asks in the book @@ -150,8 +151,8 @@ namespace CryptoExchange.Net.OrderBook Symbol = symbol; Status = OrderBookStatus.Disconnected; - asks = new SortedList(); - bids = new SortedList(new DescComparer()); + asks = new SortedList(); + bids = new SortedList(new DescComparer()); log = new Log { Level = options.LogVerbosity }; var writers = options.LogWriters ?? new List { new DebugTextWriter() }; @@ -177,7 +178,7 @@ namespace CryptoExchange.Net.OrderBook subscription = startResult.Data; subscription.ConnectionLost += Reset; - subscription.ConnectionRestored += (time) => Resync(); + subscription.ConnectionRestored += time => Resync(); Status = OrderBookStatus.Synced; return new CallResult(true, null); } @@ -194,7 +195,7 @@ namespace CryptoExchange.Net.OrderBook private void Resync() { Status = OrderBookStatus.Syncing; - bool success = false; + var success = false; while (!success) { if (Status != OrderBookStatus.Syncing) @@ -289,7 +290,7 @@ namespace CryptoExchange.Net.OrderBook if (!bookSet) { - var entry = new ProcessBufferEntry() + var entry = new ProcessBufferEntry { FirstSequence = firstSequenceNumber, LastSequence = lastSequenceNumber, @@ -350,25 +351,25 @@ namespace CryptoExchange.Net.OrderBook var listToChange = type == OrderBookEntryType.Ask ? asks : bids; if (entry.Quantity == 0) { - var bookEntry = listToChange.SingleOrDefault(i => i.Key == entry.Price); - if (!bookEntry.Equals(default(KeyValuePair))) - { - listToChange.Remove(entry.Price); - if (type == OrderBookEntryType.Ask) AskCount--; - else BidCount--; - } + if (!listToChange.ContainsKey(entry.Price)) + return; + + listToChange.Remove(entry.Price); + if (type == OrderBookEntryType.Ask) AskCount--; + else BidCount--; } else { - var bookEntry = listToChange.SingleOrDefault(i => i.Key == entry.Price); - if (bookEntry.Equals(default(KeyValuePair))) + if (!listToChange.ContainsKey(entry.Price)) { listToChange.Add(entry.Price, new OrderBookEntry(entry.Price, entry.Quantity)); if (type == OrderBookEntryType.Ask) AskCount++; else BidCount++; } else - bookEntry.Value.Quantity = entry.Quantity; + { + listToChange[entry.Price].Quantity = entry.Quantity; + } } } diff --git a/CryptoExchange.Net/RateLimiter/RateLimiterAPIKey.cs b/CryptoExchange.Net/RateLimiter/RateLimiterAPIKey.cs index ce8d9e0..2e8ea4f 100644 --- a/CryptoExchange.Net/RateLimiter/RateLimiterAPIKey.cs +++ b/CryptoExchange.Net/RateLimiter/RateLimiterAPIKey.cs @@ -35,7 +35,7 @@ namespace CryptoExchange.Net.RateLimiter if(client.authProvider?.Credentials == null) return new CallResult(0, null); - string key = client.authProvider.Credentials.Key.GetString(); + var key = client.authProvider.Credentials.Key.GetString(); int waitTime; RateLimitObject rlo; diff --git a/CryptoExchange.Net/Requests/Request.cs b/CryptoExchange.Net/Requests/Request.cs index 5566699..611f38c 100644 --- a/CryptoExchange.Net/Requests/Request.cs +++ b/CryptoExchange.Net/Requests/Request.cs @@ -14,7 +14,7 @@ namespace CryptoExchange.Net.Requests private readonly WebRequest request; /// - /// Create request object for webrequest + /// Create request object for web request /// /// public Request(WebRequest request) diff --git a/CryptoExchange.Net/RestClient.cs b/CryptoExchange.Net/RestClient.cs index 88fe5eb..c73f25b 100644 --- a/CryptoExchange.Net/RestClient.cs +++ b/CryptoExchange.Net/RestClient.cs @@ -126,14 +126,14 @@ namespace CryptoExchange.Net catch(PingException e) { if (e.InnerException == null) - return new CallResult(0, new CantConnectError() {Message = "Ping failed: " + e.Message}); + return new CallResult(0, new CantConnectError {Message = "Ping failed: " + e.Message}); if (e.InnerException is SocketException exception) - return new CallResult(0, new CantConnectError() { Message = "Ping failed: " + exception.SocketErrorCode }); - return new CallResult(0, new CantConnectError() { Message = "Ping failed: " + e.InnerException.Message }); + return new CallResult(0, new CantConnectError { Message = "Ping failed: " + exception.SocketErrorCode }); + return new CallResult(0, new CantConnectError { Message = "Ping failed: " + e.InnerException.Message }); } - return reply.Status == IPStatus.Success ? new CallResult(reply.RoundtripTime, null) : new CallResult(0, new CantConnectError() { Message = "Ping failed: " + reply.Status }); + return reply.Status == IPStatus.Success ? new CallResult(reply.RoundtripTime, null) : new CallResult(0, new CantConnectError { Message = "Ping failed: " + reply.Status }); } /// @@ -280,7 +280,7 @@ namespace CryptoExchange.Net } else if(requestBodyFormat == RequestBodyFormat.FormData) { - var formData = HttpUtility.ParseQueryString(String.Empty); + var formData = HttpUtility.ParseQueryString(string.Empty); foreach (var kvp in parameters.OrderBy(p => p.Key)) formData.Add(kvp.Key, kvp.Value.ToString()); var stringData = formData.ToString(); @@ -320,19 +320,24 @@ namespace CryptoExchange.Net try { - using (var reader = new StreamReader(response.GetResponseStream())) + var responseStream = response?.GetResponseStream(); + if (response != null && responseStream != null) { - returnedData = await reader.ReadToEndAsync().ConfigureAwait(false); - log.Write(LogVerbosity.Warning, "Server returned an error: " + returnedData); + using (var reader = new StreamReader(responseStream)) + { + returnedData = await reader.ReadToEndAsync().ConfigureAwait(false); + log.Write(LogVerbosity.Warning, "Server returned an error: " + returnedData); + } + + response.Close(); + + var jsonResult = ValidateJson(returnedData); + return !jsonResult.Success ? new WebCallResult(statusCode, returnHeaders, null, jsonResult.Error) : new WebCallResult(statusCode, returnHeaders, null, ParseErrorResponse(jsonResult.Data)); } - - response.Close(); - - var jsonResult = ValidateJson(returnedData); - return !jsonResult.Success ? new WebCallResult(statusCode, returnHeaders, null, jsonResult.Error) : new WebCallResult(statusCode, returnHeaders, null, ParseErrorResponse(jsonResult.Data)); } - catch (Exception) + catch (Exception e) { + log.Write(LogVerbosity.Debug, "Not able to read server response: " + e.Message); } var infoMessage = "No response from server"; diff --git a/CryptoExchange.Net/SocketClient.cs b/CryptoExchange.Net/SocketClient.cs index 9558e73..f2f8afd 100644 --- a/CryptoExchange.Net/SocketClient.cs +++ b/CryptoExchange.Net/SocketClient.cs @@ -141,7 +141,7 @@ namespace CryptoExchange.Net { SocketConnection socket; SocketSubscription handler; - bool released = false; + var released = false; await semaphoreSlim.WaitAsync().ConfigureAwait(false); try { @@ -193,13 +193,7 @@ namespace CryptoExchange.Net protected internal virtual async Task> SubscribeAndWait(SocketConnection socket, object request, SocketSubscription subscription) { CallResult callResult = null; - await socket.SendAndWait(request, ResponseTimeout, (data) => - { - if (!HandleSubscriptionResponse(socket, subscription, request, data, out callResult)) - return false; - - return true; - }).ConfigureAwait(false); + await socket.SendAndWait(request, ResponseTimeout, data => HandleSubscriptionResponse(socket, subscription, request, data, out callResult)).ConfigureAwait(false); if (callResult?.Success == true) subscription.Confirmed = true; @@ -210,7 +204,7 @@ namespace CryptoExchange.Net /// /// Query for data /// - /// Exepected result type + /// Expected result type /// The request to send /// Whether the socket should be authenticated /// @@ -230,7 +224,7 @@ namespace CryptoExchange.Net protected virtual async Task> Query(string url, object request, bool authenticated) { SocketConnection socket; - bool released = false; + var released = false; await semaphoreSlim.WaitAsync().ConfigureAwait(false); try { @@ -244,7 +238,7 @@ namespace CryptoExchange.Net var connectResult = await ConnectIfNeeded(socket, authenticated).ConfigureAwait(false); if (!connectResult.Success) - return new CallResult(default(T), connectResult.Error); + return new CallResult(default, connectResult.Error); } finally { @@ -257,7 +251,7 @@ namespace CryptoExchange.Net if (socket.PausedActivity) { log.Write(LogVerbosity.Info, "Socket has been paused, can't send query at this moment"); - return new CallResult(default(T), new ServerError("Socket is paused")); + return new CallResult(default, new ServerError("Socket is paused")); } return await QueryAndWait(socket, request).ConfigureAwait(false); @@ -272,8 +266,8 @@ namespace CryptoExchange.Net /// protected virtual async Task> QueryAndWait(SocketConnection socket, object request) { - CallResult dataResult = new CallResult(default(T), new ServerError("No response on query received")); - await socket.SendAndWait(request, ResponseTimeout, (data) => + var dataResult = new CallResult(default, new ServerError("No response on query received")); + await socket.SendAndWait(request, ResponseTimeout, data => { if (!HandleQueryResponse(socket, request, data, out var callResult)) return false; @@ -293,28 +287,25 @@ namespace CryptoExchange.Net /// protected virtual async Task> ConnectIfNeeded(SocketConnection socket, bool authenticated) { - if (!socket.Connected) + if (socket.Connected) + return new CallResult(true, null); + + var connectResult = await ConnectSocket(socket).ConfigureAwait(false); + if (!connectResult.Success) + return new CallResult(false, new CantConnectError()); + + if (!authenticated || socket.Authenticated) + return new CallResult(true, null); + + var result = await AuthenticateSocket(socket).ConfigureAwait(false); + if (!result.Success) { - var connectResult = await ConnectSocket(socket).ConfigureAwait(false); - if (!connectResult.Success) - { - return new CallResult(false, new CantConnectError()); - } - - if (authenticated && !socket.Authenticated) - { - var result = await AuthenticateSocket(socket).ConfigureAwait(false); - if (!result.Success) - { - log.Write(LogVerbosity.Warning, "Socket authentication failed"); - result.Error.Message = "Authentication failed: " + result.Error.Message; - return new CallResult(false, result.Error); - } - - socket.Authenticated = true; - } + log.Write(LogVerbosity.Warning, "Socket authentication failed"); + result.Error.Message = "Authentication failed: " + result.Error.Message; + return new CallResult(false, result.Error); } + socket.Authenticated = true; return new CallResult(true, null); } @@ -388,11 +379,11 @@ namespace CryptoExchange.Net /// protected virtual SocketSubscription AddHandler(object request, string identifier, bool userSubscription, SocketConnection connection, Action dataHandler) { - Action internalHandler = (socketWrapper, data) => + void InternalHandler(SocketConnection socketWrapper, JToken data) { if (typeof(T) == typeof(string)) { - dataHandler((T)Convert.ChangeType(data.ToString(), typeof(T))); + dataHandler((T) Convert.ChangeType(data.ToString(), typeof(T))); return; } @@ -404,11 +395,9 @@ namespace CryptoExchange.Net } dataHandler(desResult.Data); - }; + } - if (request != null) - return connection.AddHandler(request, userSubscription, internalHandler); - return connection.AddHandler(identifier, userSubscription, internalHandler); + return connection.AddHandler(request ?? identifier, userSubscription, InternalHandler); } /// @@ -515,16 +504,16 @@ namespace CryptoExchange.Net break; var obj = objGetter(socket); - if (obj != null) + if (obj == null) + continue; + + try { - try - { - socket.Send(obj); - } - catch (Exception ex) - { - log.Write(LogVerbosity.Warning, "Periodic send failed: " + ex); - } + socket.Send(obj); + } + catch (Exception ex) + { + log.Write(LogVerbosity.Warning, "Periodic send failed: " + ex); } } } diff --git a/CryptoExchange.Net/Sockets/BaseSocket.cs b/CryptoExchange.Net/Sockets/BaseSocket.cs index fee144a..0e8d5c6 100644 --- a/CryptoExchange.Net/Sockets/BaseSocket.cs +++ b/CryptoExchange.Net/Sockets/BaseSocket.cs @@ -16,7 +16,7 @@ namespace CryptoExchange.Net.Sockets /// /// Socket implementation /// - public class BaseSocket: IWebsocket + internal class BaseSocket: IWebsocket { internal static int lastStreamId; private static readonly object streamIdLock = new object(); @@ -153,7 +153,7 @@ namespace CryptoExchange.Net.Sockets if (DateTime.UtcNow - LastActionTime > Timeout) { log.Write(LogVerbosity.Warning, $"No data received for {Timeout}, reconnecting socket"); - Close().ConfigureAwait(false); + _ = Close().ConfigureAwait(false); return; } } @@ -267,7 +267,7 @@ namespace CryptoExchange.Net.Sockets if (connected) { log?.Write(LogVerbosity.Debug, $"Socket {Id} connected"); - if ((timeoutTask == null || timeoutTask.IsCompleted) && Timeout != default(TimeSpan)) + if ((timeoutTask == null || timeoutTask.IsCompleted) && Timeout != default) timeoutTask = Task.Run(CheckTimeout); } else diff --git a/CryptoExchange.Net/Sockets/SocketConnection.cs b/CryptoExchange.Net/Sockets/SocketConnection.cs index 2bb0df3..a13585e 100644 --- a/CryptoExchange.Net/Sockets/SocketConnection.cs +++ b/CryptoExchange.Net/Sockets/SocketConnection.cs @@ -172,7 +172,7 @@ namespace CryptoExchange.Net.Sockets SocketSubscription currentSubscription = null; try { - bool handled = false; + var handled = false; var sw = Stopwatch.StartNew(); lock (handlersLock) { @@ -387,7 +387,7 @@ namespace CryptoExchange.Net.Sockets if (subscription.Confirmed) await socketClient.Unsubscribe(this, subscription).ConfigureAwait(false); - bool shouldCloseWrapper = false; + var shouldCloseWrapper = false; lock (handlersLock) { handlers.Remove(subscription);