From 694dc5cbbbb99a0c96a5600a11c0555dabbe45de Mon Sep 17 00:00:00 2001 From: MartyIX <203266+MartyIX@users.noreply.github.com> Date: Thu, 27 Aug 2020 14:06:08 +0200 Subject: [PATCH 01/22] ExtensionMethods: Add `parameterName` when throwing `ArgumentException`. --- CryptoExchange.Net/ExtensionMethods.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/CryptoExchange.Net/ExtensionMethods.cs b/CryptoExchange.Net/ExtensionMethods.cs index 1ac235b..3f1df21 100644 --- a/CryptoExchange.Net/ExtensionMethods.cs +++ b/CryptoExchange.Net/ExtensionMethods.cs @@ -172,7 +172,7 @@ namespace CryptoExchange.Net tokenRegistration.Dispose(); } } - + /// /// Wait one async /// @@ -225,7 +225,7 @@ namespace CryptoExchange.Net { if (!allowedValues.Contains(value)) throw new ArgumentException( - $"{value} not allowed for parameter {argumentName}, allowed values: {string.Join(", ", allowedValues)}"); + $"{value} not allowed for parameter {argumentName}, allowed values: {string.Join(", ", allowedValues)}", argumentName); } /// @@ -239,7 +239,7 @@ namespace CryptoExchange.Net { if (value < minValue || value > maxValue) throw new ArgumentException( - $"{value} not allowed for parameter {argumentName}, min: {minValue}, max: {maxValue}"); + $"{value} not allowed for parameter {argumentName}, min: {minValue}, max: {maxValue}", argumentName); } /// @@ -250,7 +250,7 @@ namespace CryptoExchange.Net public static void ValidateNotNull(this string value, string argumentName) { if (string.IsNullOrEmpty(value)) - throw new ArgumentException($"No value provided for parameter {argumentName}"); + throw new ArgumentException($"No value provided for parameter {argumentName}", argumentName); } /// @@ -261,7 +261,7 @@ namespace CryptoExchange.Net public static void ValidateNotNull(this object value, string argumentName) { if (value == null) - throw new ArgumentException($"No value provided for parameter {argumentName}"); + throw new ArgumentException($"No value provided for parameter {argumentName}", argumentName); } /// @@ -272,7 +272,7 @@ namespace CryptoExchange.Net public static void ValidateNotNull(this IEnumerable value, string argumentName) { if (value == null || !value.Any()) - throw new ArgumentException($"No values provided for parameter {argumentName}"); + throw new ArgumentException($"No values provided for parameter {argumentName}", argumentName); } } } From f8d86545c7b7d483069a54bd7da292bce0f63270 Mon Sep 17 00:00:00 2001 From: JKorf Date: Fri, 28 Aug 2020 11:46:01 +0200 Subject: [PATCH 02/22] Update CryptoExchange.Net.xml --- CryptoExchange.Net/CryptoExchange.Net.xml | 143 ++++++++++++++++++++++ 1 file changed, 143 insertions(+) diff --git a/CryptoExchange.Net/CryptoExchange.Net.xml b/CryptoExchange.Net/CryptoExchange.Net.xml index e495b2c..d854184 100644 --- a/CryptoExchange.Net/CryptoExchange.Net.xml +++ b/CryptoExchange.Net/CryptoExchange.Net.xml @@ -2986,5 +2986,148 @@ + + + Specifies that is allowed as an input even if the + corresponding type disallows it. + + + + + Initializes a new instance of the class. + + + + + Specifies that is disallowed as an input even if the + corresponding type allows it. + + + + + Initializes a new instance of the class. + + + + + Specifies that a method that will never return under any circumstance. + + + + + Initializes a new instance of the class. + + + + + Specifies that the method will not return if the associated + parameter is passed the specified value. + + + + + Gets the condition parameter value. + Code after the method is considered unreachable by diagnostics if the argument + to the associated parameter matches this value. + + + + + Initializes a new instance of the + class with the specified parameter value. + + + The condition parameter value. + Code after the method is considered unreachable by diagnostics if the argument + to the associated parameter matches this value. + + + + + Specifies that an output may be even if the + corresponding type disallows it. + + + + + Initializes a new instance of the class. + + + + + Specifies that when a method returns , + the parameter may be even if the corresponding type disallows it. + + + + + Gets the return value condition. + If the method returns this value, the associated parameter may be . + + + + + Initializes the attribute with the specified return value condition. + + + The return value condition. + If the method returns this value, the associated parameter may be . + + + + + Specifies that an output is not even if the + corresponding type allows it. + + + + + Initializes a new instance of the class. + + + + + Specifies that the output will be non- if the + named parameter is non-. + + + + + Gets the associated parameter name. + The output will be non- if the argument to the + parameter specified is non-. + + + + + Initializes the attribute with the associated parameter name. + + + The associated parameter name. + The output will be non- if the argument to the + parameter specified is non-. + + + + + Specifies that when a method returns , + the parameter will not be even if the corresponding type allows it. + + + + + Gets the return value condition. + If the method returns this value, the associated parameter will not be . + + + + + Initializes the attribute with the specified return value condition. + + + The return value condition. + If the method returns this value, the associated parameter will not be . + + From 0496f03b7448f2f87ae44e10081016e46fd35d20 Mon Sep 17 00:00:00 2001 From: JKorf Date: Fri, 28 Aug 2020 13:13:24 +0200 Subject: [PATCH 03/22] Fix for logging in order book --- CryptoExchange.Net/CryptoExchange.Net.xml | 143 ------------------ .../OrderBook/SymbolOrderBook.cs | 2 +- 2 files changed, 1 insertion(+), 144 deletions(-) diff --git a/CryptoExchange.Net/CryptoExchange.Net.xml b/CryptoExchange.Net/CryptoExchange.Net.xml index d854184..e495b2c 100644 --- a/CryptoExchange.Net/CryptoExchange.Net.xml +++ b/CryptoExchange.Net/CryptoExchange.Net.xml @@ -2986,148 +2986,5 @@ - - - Specifies that is allowed as an input even if the - corresponding type disallows it. - - - - - Initializes a new instance of the class. - - - - - Specifies that is disallowed as an input even if the - corresponding type allows it. - - - - - Initializes a new instance of the class. - - - - - Specifies that a method that will never return under any circumstance. - - - - - Initializes a new instance of the class. - - - - - Specifies that the method will not return if the associated - parameter is passed the specified value. - - - - - Gets the condition parameter value. - Code after the method is considered unreachable by diagnostics if the argument - to the associated parameter matches this value. - - - - - Initializes a new instance of the - class with the specified parameter value. - - - The condition parameter value. - Code after the method is considered unreachable by diagnostics if the argument - to the associated parameter matches this value. - - - - - Specifies that an output may be even if the - corresponding type disallows it. - - - - - Initializes a new instance of the class. - - - - - Specifies that when a method returns , - the parameter may be even if the corresponding type disallows it. - - - - - Gets the return value condition. - If the method returns this value, the associated parameter may be . - - - - - Initializes the attribute with the specified return value condition. - - - The return value condition. - If the method returns this value, the associated parameter may be . - - - - - Specifies that an output is not even if the - corresponding type allows it. - - - - - Initializes a new instance of the class. - - - - - Specifies that the output will be non- if the - named parameter is non-. - - - - - Gets the associated parameter name. - The output will be non- if the argument to the - parameter specified is non-. - - - - - Initializes the attribute with the associated parameter name. - - - The associated parameter name. - The output will be non- if the argument to the - parameter specified is non-. - - - - - Specifies that when a method returns , - the parameter will not be even if the corresponding type allows it. - - - - - Gets the return value condition. - If the method returns this value, the associated parameter will not be . - - - - - Initializes the attribute with the specified return value condition. - - - The return value condition. - If the method returns this value, the associated parameter will not be . - - diff --git a/CryptoExchange.Net/OrderBook/SymbolOrderBook.cs b/CryptoExchange.Net/OrderBook/SymbolOrderBook.cs index cb15451..c0e8bbf 100644 --- a/CryptoExchange.Net/OrderBook/SymbolOrderBook.cs +++ b/CryptoExchange.Net/OrderBook/SymbolOrderBook.cs @@ -377,7 +377,7 @@ namespace CryptoExchange.Net.OrderBook FirstUpdateId = item.StartUpdateId, LastUpdateId = item.EndUpdateId, }); - log.Write(LogVerbosity.Debug, $"{Id} order book {Symbol} update buffered #{item.StartUpdateId}-#{item.EndUpdateId} [{Asks.Count()} asks, {Bids.Count()} bids]"); + log.Write(LogVerbosity.Debug, $"{Id} order book {Symbol} update buffered #{item.StartUpdateId}-#{item.EndUpdateId} [{item.Asks.Count()} asks, {item.Bids.Count()} bids]"); } else { From f0e020d2ebc1541eba098d20ce444bde324bc480 Mon Sep 17 00:00:00 2001 From: JKorf Date: Tue, 6 Oct 2020 16:52:12 +0200 Subject: [PATCH 04/22] Changed default ShouldCheckObjects to false --- CryptoExchange.Net/CryptoExchange.Net.xml | 145 ++++++++++++++++++++++ CryptoExchange.Net/Objects/Options.cs | 2 +- 2 files changed, 146 insertions(+), 1 deletion(-) diff --git a/CryptoExchange.Net/CryptoExchange.Net.xml b/CryptoExchange.Net/CryptoExchange.Net.xml index e495b2c..c8b3776 100644 --- a/CryptoExchange.Net/CryptoExchange.Net.xml +++ b/CryptoExchange.Net/CryptoExchange.Net.xml @@ -2988,3 +2988,148 @@ +System.Diagnostics.CodeAnalysis.AllowNullAttribute"> + + Specifies that is allowed as an input even if the + corresponding type disallows it. + + + + + Initializes a new instance of the class. + + + + + Specifies that is disallowed as an input even if the + corresponding type allows it. + + + + + Initializes a new instance of the class. + + + + + Specifies that a method that will never return under any circumstance. + + + + + Initializes a new instance of the class. + + + + + Specifies that the method will not return if the associated + parameter is passed the specified value. + + + + + Gets the condition parameter value. + Code after the method is considered unreachable by diagnostics if the argument + to the associated parameter matches this value. + + + + + Initializes a new instance of the + class with the specified parameter value. + + + The condition parameter value. + Code after the method is considered unreachable by diagnostics if the argument + to the associated parameter matches this value. + + + + + Specifies that an output may be even if the + corresponding type disallows it. + + + + + Initializes a new instance of the class. + + + + + Specifies that when a method returns , + the parameter may be even if the corresponding type disallows it. + + + + + Gets the return value condition. + If the method returns this value, the associated parameter may be . + + + + + Initializes the attribute with the specified return value condition. + + + The return value condition. + If the method returns this value, the associated parameter may be . + + + + + Specifies that an output is not even if the + corresponding type allows it. + + + + + Initializes a new instance of the class. + + + + + Specifies that the output will be non- if the + named parameter is non-. + + + + + Gets the associated parameter name. + The output will be non- if the argument to the + parameter specified is non-. + + + + + Initializes the attribute with the associated parameter name. + + + The associated parameter name. + The output will be non- if the argument to the + parameter specified is non-. + + + + + Specifies that when a method returns , + the parameter will not be even if the corresponding type allows it. + + + + + Gets the return value condition. + If the method returns this value, the associated parameter will not be . + + + + + Initializes the attribute with the specified return value condition. + + + The return value condition. + If the method returns this value, the associated parameter will not be . + + + + diff --git a/CryptoExchange.Net/Objects/Options.cs b/CryptoExchange.Net/Objects/Options.cs index cc3cd9b..1f43e63 100644 --- a/CryptoExchange.Net/Objects/Options.cs +++ b/CryptoExchange.Net/Objects/Options.cs @@ -89,7 +89,7 @@ namespace CryptoExchange.Net.Objects /// /// Should check objects for missing properties based on the model and the received JSON /// - public bool ShouldCheckObjects { get; set; } = true; + public bool ShouldCheckObjects { get; set; } = false; /// /// Proxy to use From 133279b28bbeb50ad8d716e3c54773d2617de24f Mon Sep 17 00:00:00 2001 From: JKorf Date: Tue, 6 Oct 2020 17:19:35 +0200 Subject: [PATCH 05/22] Updated version --- CryptoExchange.Net/CryptoExchange.Net.csproj | 4 +- CryptoExchange.Net/CryptoExchange.Net.xml | 145 ------------------- README.md | 3 + 3 files changed, 5 insertions(+), 147 deletions(-) diff --git a/CryptoExchange.Net/CryptoExchange.Net.csproj b/CryptoExchange.Net/CryptoExchange.Net.csproj index 58187b3..d20579e 100644 --- a/CryptoExchange.Net/CryptoExchange.Net.csproj +++ b/CryptoExchange.Net/CryptoExchange.Net.csproj @@ -6,12 +6,12 @@ CryptoExchange.Net JKorf A base package for implementing cryptocurrency exchange API's - 3.0.14 + 3.0.15 false https://github.com/JKorf/CryptoExchange.Net en true - 3.0.14 - Updated exception message logging + 3.0.15 - Changed default ShouldCheckObjects to false to prevent spam in logging enable 8.0 MIT diff --git a/CryptoExchange.Net/CryptoExchange.Net.xml b/CryptoExchange.Net/CryptoExchange.Net.xml index c8b3776..e495b2c 100644 --- a/CryptoExchange.Net/CryptoExchange.Net.xml +++ b/CryptoExchange.Net/CryptoExchange.Net.xml @@ -2988,148 +2988,3 @@ -System.Diagnostics.CodeAnalysis.AllowNullAttribute"> - - Specifies that is allowed as an input even if the - corresponding type disallows it. - - - - - Initializes a new instance of the class. - - - - - Specifies that is disallowed as an input even if the - corresponding type allows it. - - - - - Initializes a new instance of the class. - - - - - Specifies that a method that will never return under any circumstance. - - - - - Initializes a new instance of the class. - - - - - Specifies that the method will not return if the associated - parameter is passed the specified value. - - - - - Gets the condition parameter value. - Code after the method is considered unreachable by diagnostics if the argument - to the associated parameter matches this value. - - - - - Initializes a new instance of the - class with the specified parameter value. - - - The condition parameter value. - Code after the method is considered unreachable by diagnostics if the argument - to the associated parameter matches this value. - - - - - Specifies that an output may be even if the - corresponding type disallows it. - - - - - Initializes a new instance of the class. - - - - - Specifies that when a method returns , - the parameter may be even if the corresponding type disallows it. - - - - - Gets the return value condition. - If the method returns this value, the associated parameter may be . - - - - - Initializes the attribute with the specified return value condition. - - - The return value condition. - If the method returns this value, the associated parameter may be . - - - - - Specifies that an output is not even if the - corresponding type allows it. - - - - - Initializes a new instance of the class. - - - - - Specifies that the output will be non- if the - named parameter is non-. - - - - - Gets the associated parameter name. - The output will be non- if the argument to the - parameter specified is non-. - - - - - Initializes the attribute with the associated parameter name. - - - The associated parameter name. - The output will be non- if the argument to the - parameter specified is non-. - - - - - Specifies that when a method returns , - the parameter will not be even if the corresponding type allows it. - - - - - Gets the return value condition. - If the method returns this value, the associated parameter will not be . - - - - - Initializes the attribute with the specified return value condition. - - - The return value condition. - If the method returns this value, the associated parameter will not be . - - - - diff --git a/README.md b/README.md index 99a06e2..d2e597a 100644 --- a/README.md +++ b/README.md @@ -199,6 +199,9 @@ The order book will automatically reconnect when the connection is lost and resy To stop synchronizing an order book use the `Stop` method. ## Release notes +* Version 3.0.15 - 06 Oct 2020 + * Changed default ShouldCheckObjects to false to prevent spam in logging + * Version 3.0.14 - 24 Aug 2020 * Updated exception message logging From 48a2c095a49b1e8c5cf35311a3252636078bd087 Mon Sep 17 00:00:00 2001 From: JKorf Date: Wed, 7 Oct 2020 08:31:43 +0200 Subject: [PATCH 06/22] Fix for credentials reading from file, adjusted client options base adress to always end on a / --- .../Authentication/ApiCredentials.cs | 2 +- CryptoExchange.Net/Objects/Options.cs | 14 +++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/CryptoExchange.Net/Authentication/ApiCredentials.cs b/CryptoExchange.Net/Authentication/ApiCredentials.cs index f863fcd..8900db9 100644 --- a/CryptoExchange.Net/Authentication/ApiCredentials.cs +++ b/CryptoExchange.Net/Authentication/ApiCredentials.cs @@ -80,7 +80,7 @@ namespace CryptoExchange.Net.Authentication /// A key to identify the credentials for the API. For example, when set to `binanceSecret` the json data should contain a value for the property `binanceSecret`. Defaults to 'apiSecret'. public ApiCredentials(Stream inputStream, string? identifierKey = null, string? identifierSecret = null) { - using var reader = new StreamReader(inputStream, Encoding.ASCII, false, 512, true); + using var reader = new StreamReader(inputStream, Encoding.UTF8, false, 512, true); var stringData = reader.ReadToEnd(); var jsonData = stringData.ToJToken(); diff --git a/CryptoExchange.Net/Objects/Options.cs b/CryptoExchange.Net/Objects/Options.cs index 1f43e63..ee8f2ae 100644 --- a/CryptoExchange.Net/Objects/Options.cs +++ b/CryptoExchange.Net/Objects/Options.cs @@ -76,10 +76,22 @@ namespace CryptoExchange.Net.Objects /// public class ClientOptions : BaseOptions { + private string _baseAddress; + /// /// The base address of the client /// - public string BaseAddress { get; set; } + public string BaseAddress + { + get => _baseAddress; + set + { + var newValue = value; + if (!newValue.EndsWith("/")) + newValue += "/"; + _baseAddress = newValue; + } + } /// /// The api credentials From 9da7683291bf6a2b48ab63700a6cc994438dc873 Mon Sep 17 00:00:00 2001 From: JKorf Date: Wed, 7 Oct 2020 09:23:42 +0200 Subject: [PATCH 07/22] Added GetResultOrError on CallResult for nullability --- CryptoExchange.Net/CryptoExchange.Net.xml | 151 ++++++++++++++++++++++ CryptoExchange.Net/Objects/CallResult.cs | 24 ++++ 2 files changed, 175 insertions(+) diff --git a/CryptoExchange.Net/CryptoExchange.Net.xml b/CryptoExchange.Net/CryptoExchange.Net.xml index e495b2c..da22b52 100644 --- a/CryptoExchange.Net/CryptoExchange.Net.xml +++ b/CryptoExchange.Net/CryptoExchange.Net.xml @@ -1233,6 +1233,14 @@ + + + Whether the call was successful or not. Useful for nullability checking. + + The data returned by the call. + on failure. + true when succeeded, false otherwise. + The result of a request @@ -2986,5 +2994,148 @@ + + + Specifies that is allowed as an input even if the + corresponding type disallows it. + + + + + Initializes a new instance of the class. + + + + + Specifies that is disallowed as an input even if the + corresponding type allows it. + + + + + Initializes a new instance of the class. + + + + + Specifies that a method that will never return under any circumstance. + + + + + Initializes a new instance of the class. + + + + + Specifies that the method will not return if the associated + parameter is passed the specified value. + + + + + Gets the condition parameter value. + Code after the method is considered unreachable by diagnostics if the argument + to the associated parameter matches this value. + + + + + Initializes a new instance of the + class with the specified parameter value. + + + The condition parameter value. + Code after the method is considered unreachable by diagnostics if the argument + to the associated parameter matches this value. + + + + + Specifies that an output may be even if the + corresponding type disallows it. + + + + + Initializes a new instance of the class. + + + + + Specifies that when a method returns , + the parameter may be even if the corresponding type disallows it. + + + + + Gets the return value condition. + If the method returns this value, the associated parameter may be . + + + + + Initializes the attribute with the specified return value condition. + + + The return value condition. + If the method returns this value, the associated parameter may be . + + + + + Specifies that an output is not even if the + corresponding type allows it. + + + + + Initializes a new instance of the class. + + + + + Specifies that the output will be non- if the + named parameter is non-. + + + + + Gets the associated parameter name. + The output will be non- if the argument to the + parameter specified is non-. + + + + + Initializes the attribute with the associated parameter name. + + + The associated parameter name. + The output will be non- if the argument to the + parameter specified is non-. + + + + + Specifies that when a method returns , + the parameter will not be even if the corresponding type allows it. + + + + + Gets the return value condition. + If the method returns this value, the associated parameter will not be . + + + + + Initializes the attribute with the specified return value condition. + + + The return value condition. + If the method returns this value, the associated parameter will not be . + + diff --git a/CryptoExchange.Net/Objects/CallResult.cs b/CryptoExchange.Net/Objects/CallResult.cs index 9253ead..a47e51a 100644 --- a/CryptoExchange.Net/Objects/CallResult.cs +++ b/CryptoExchange.Net/Objects/CallResult.cs @@ -42,6 +42,30 @@ namespace CryptoExchange.Net.Objects { return obj?.Success == true; } + + /// + /// Whether the call was successful or not. Useful for nullability checking. + /// + /// The data returned by the call. + /// on failure. + /// true when succeeded, false otherwise. + public bool GetResultOrError([MaybeNullWhen(false)] out T data, [NotNullWhen(false)] out Error? error) + { + if (Success) + { + data = Data!; + error = null; + + return true; + } + else + { + data = default; + error = Error!; + + return false; + } + } } /// From 6d7cbbb4366e51655fd1f3bb64d6b82faaffac01 Mon Sep 17 00:00:00 2001 From: JKorf Date: Thu, 8 Oct 2020 09:05:50 +0200 Subject: [PATCH 08/22] Added CallResult without type parameter for calls which don't return anything --- CryptoExchange.Net/CryptoExchange.Net.xml | 96 ++++++++++++++---- CryptoExchange.Net/Objects/CallResult.cs | 118 ++++++++++++++++++---- 2 files changed, 174 insertions(+), 40 deletions(-) diff --git a/CryptoExchange.Net/CryptoExchange.Net.xml b/CryptoExchange.Net/CryptoExchange.Net.xml index da22b52..9e81788 100644 --- a/CryptoExchange.Net/CryptoExchange.Net.xml +++ b/CryptoExchange.Net/CryptoExchange.Net.xml @@ -1199,6 +1199,40 @@ + + + The result of an operation + + + + + An error if the call didn't succeed + + + + + Whether the call was successful + + + + + ctor + + + + + + Overwrite bool check so we can use if(callResult) instead of if(callResult.Success) + + + + + + Create an error result + + + + The result of an operation @@ -1210,16 +1244,6 @@ The data returned by the call - - - An error if the call didn't succeed - - - - - Whether the call was successful - - ctor @@ -1238,9 +1262,48 @@ Whether the call was successful or not. Useful for nullability checking. The data returned by the call. - on failure. + on failure. true when succeeded, false otherwise. + + + Create an error result + + + + + + + The result of a request + + + + + The status code of the response. Note that a OK status does not always indicate success, check the Success parameter for this. + + + + + The response headers + + + + + ctor + + + + + + + + Create an error result + + + + + + The result of a request @@ -1266,13 +1329,6 @@ - - - Create an error result - - - - Create an error result @@ -2994,7 +3050,9 @@ - + + +System.Diagnostics.CodeAnalysis.AllowNullAttribute"> Specifies that is allowed as an input even if the corresponding type disallows it. diff --git a/CryptoExchange.Net/Objects/CallResult.cs b/CryptoExchange.Net/Objects/CallResult.cs index a47e51a..f3be273 100644 --- a/CryptoExchange.Net/Objects/CallResult.cs +++ b/CryptoExchange.Net/Objects/CallResult.cs @@ -7,13 +7,8 @@ namespace CryptoExchange.Net.Objects /// /// The result of an operation /// - /// - public class CallResult + public class CallResult { - /// - /// The data returned by the call - /// - public T Data { get; internal set; } /// /// An error if the call didn't succeed /// @@ -23,15 +18,54 @@ namespace CryptoExchange.Net.Objects /// public bool Success => Error == null; + /// + /// ctor + /// + /// + public CallResult(Error? error) + { + Error = error; + } + + /// + /// Overwrite bool check so we can use if(callResult) instead of if(callResult.Success) + /// + /// + public static implicit operator bool(CallResult obj) + { + return obj?.Success == true; + } + + /// + /// Create an error result + /// + /// + /// + public static WebCallResult CreateErrorResult(Error error) + { + return new WebCallResult(null, null, error); + } + } + + /// + /// The result of an operation + /// + /// + public class CallResult: CallResult + { + /// + /// The data returned by the call + /// + public T Data { get; internal set; } + /// /// ctor /// /// /// - public CallResult([AllowNull]T data, Error? error) + public CallResult([AllowNull]T data, Error? error): base(error) { Data = data; - Error = error; } /// @@ -66,6 +100,58 @@ namespace CryptoExchange.Net.Objects return false; } } + + /// + /// Create an error result + /// + /// + /// + public new static WebCallResult CreateErrorResult(Error error) + { + return new WebCallResult(null, null, default, error); + } + } + + /// + /// The result of a request + /// + public class WebCallResult : CallResult + { + /// + /// The status code of the response. Note that a OK status does not always indicate success, check the Success parameter for this. + /// + public HttpStatusCode? ResponseStatusCode { get; set; } + + /// + /// The response headers + /// + public IEnumerable>>? ResponseHeaders { get; set; } + + /// + /// ctor + /// + /// + /// + /// + public WebCallResult( + HttpStatusCode? code, + IEnumerable>>? responseHeaders, Error? error) : base(error) + { + ResponseHeaders = responseHeaders; + ResponseStatusCode = code; + } + + /// + /// Create an error result + /// + /// + /// + /// + /// + public static WebCallResult CreateErrorResult(HttpStatusCode? code, IEnumerable>>? responseHeaders, Error error) + { + return new WebCallResult(code, responseHeaders, error); + } } /// @@ -83,7 +169,7 @@ namespace CryptoExchange.Net.Objects /// The response headers /// public IEnumerable>>? ResponseHeaders { get; set; } - + /// /// ctor /// @@ -95,18 +181,8 @@ namespace CryptoExchange.Net.Objects HttpStatusCode? code, IEnumerable>>? responseHeaders, [AllowNull] T data, Error? error): base(data, error) { - ResponseHeaders = responseHeaders; ResponseStatusCode = code; - } - - /// - /// Create an error result - /// - /// - /// - public static WebCallResult CreateErrorResult(Error error) - { - return new WebCallResult(null, null, default!, error); + ResponseHeaders = responseHeaders; } /// @@ -118,7 +194,7 @@ namespace CryptoExchange.Net.Objects /// public static WebCallResult CreateErrorResult(HttpStatusCode? code, IEnumerable>>? responseHeaders, Error error) { - return new WebCallResult(code, responseHeaders, default!, error); + return new WebCallResult(code, responseHeaders, default, error); } } } From 47a1e0bef8b117d855b184de6cdb4252af89c8c1 Mon Sep 17 00:00:00 2001 From: JKorf Date: Thu, 8 Oct 2020 09:23:16 +0200 Subject: [PATCH 09/22] Fix socket combining, fix tests --- .../RestClientTests.cs | 2 +- .../SocketClientTests.cs | 2 +- CryptoExchange.Net/CryptoExchange.Net.xml | 145 ------------------ CryptoExchange.Net/SocketClient.cs | 3 +- 4 files changed, 4 insertions(+), 148 deletions(-) diff --git a/CryptoExchange.Net.UnitTests/RestClientTests.cs b/CryptoExchange.Net.UnitTests/RestClientTests.cs index d07c5d9..7a13a62 100644 --- a/CryptoExchange.Net.UnitTests/RestClientTests.cs +++ b/CryptoExchange.Net.UnitTests/RestClientTests.cs @@ -113,7 +113,7 @@ namespace CryptoExchange.Net.UnitTests // assert - Assert.IsTrue(client.BaseAddress == "http://test.address.com"); + Assert.IsTrue(client.BaseAddress == "http://test.address.com/"); Assert.IsTrue(client.RateLimiters.Count() == 1); Assert.IsTrue(client.RateLimitBehaviour == RateLimitingBehaviour.Fail); Assert.IsTrue(client.RequestTimeout == TimeSpan.FromMinutes(1)); diff --git a/CryptoExchange.Net.UnitTests/SocketClientTests.cs b/CryptoExchange.Net.UnitTests/SocketClientTests.cs index cef45f4..f684473 100644 --- a/CryptoExchange.Net.UnitTests/SocketClientTests.cs +++ b/CryptoExchange.Net.UnitTests/SocketClientTests.cs @@ -25,7 +25,7 @@ namespace CryptoExchange.Net.UnitTests //assert - Assert.IsTrue(client.BaseAddress == "http://test.address.com"); + Assert.IsTrue(client.BaseAddress == "http://test.address.com/"); Assert.IsTrue(client.ReconnectInterval.TotalSeconds == 6); } diff --git a/CryptoExchange.Net/CryptoExchange.Net.xml b/CryptoExchange.Net/CryptoExchange.Net.xml index 9e81788..3e09b10 100644 --- a/CryptoExchange.Net/CryptoExchange.Net.xml +++ b/CryptoExchange.Net/CryptoExchange.Net.xml @@ -3052,148 +3052,3 @@ -System.Diagnostics.CodeAnalysis.AllowNullAttribute"> - - Specifies that is allowed as an input even if the - corresponding type disallows it. - - - - - Initializes a new instance of the class. - - - - - Specifies that is disallowed as an input even if the - corresponding type allows it. - - - - - Initializes a new instance of the class. - - - - - Specifies that a method that will never return under any circumstance. - - - - - Initializes a new instance of the class. - - - - - Specifies that the method will not return if the associated - parameter is passed the specified value. - - - - - Gets the condition parameter value. - Code after the method is considered unreachable by diagnostics if the argument - to the associated parameter matches this value. - - - - - Initializes a new instance of the - class with the specified parameter value. - - - The condition parameter value. - Code after the method is considered unreachable by diagnostics if the argument - to the associated parameter matches this value. - - - - - Specifies that an output may be even if the - corresponding type disallows it. - - - - - Initializes a new instance of the class. - - - - - Specifies that when a method returns , - the parameter may be even if the corresponding type disallows it. - - - - - Gets the return value condition. - If the method returns this value, the associated parameter may be . - - - - - Initializes the attribute with the specified return value condition. - - - The return value condition. - If the method returns this value, the associated parameter may be . - - - - - Specifies that an output is not even if the - corresponding type allows it. - - - - - Initializes a new instance of the class. - - - - - Specifies that the output will be non- if the - named parameter is non-. - - - - - Gets the associated parameter name. - The output will be non- if the argument to the - parameter specified is non-. - - - - - Initializes the attribute with the associated parameter name. - - - The associated parameter name. - The output will be non- if the argument to the - parameter specified is non-. - - - - - Specifies that when a method returns , - the parameter will not be even if the corresponding type allows it. - - - - - Gets the return value condition. - If the method returns this value, the associated parameter will not be . - - - - - Initializes the attribute with the specified return value condition. - - - The return value condition. - If the method returns this value, the associated parameter will not be . - - - - diff --git a/CryptoExchange.Net/SocketClient.cs b/CryptoExchange.Net/SocketClient.cs index daf83c7..5632b94 100644 --- a/CryptoExchange.Net/SocketClient.cs +++ b/CryptoExchange.Net/SocketClient.cs @@ -427,7 +427,8 @@ namespace CryptoExchange.Net /// protected virtual SocketConnection GetWebsocket(string address, bool authenticated) { - var socketResult = sockets.Where(s => s.Value.Socket.Url == address && (s.Value.Authenticated == authenticated || !authenticated) && s.Value.Connected).OrderBy(s => s.Value.HandlerCount).FirstOrDefault(); + var socketResult = sockets.Where(s => s.Value.Socket.Url == address.TrimEnd('/') + && (s.Value.Authenticated == authenticated || !authenticated) && s.Value.Connected).OrderBy(s => s.Value.HandlerCount).FirstOrDefault(); var result = socketResult.Equals(default(KeyValuePair)) ? null : socketResult.Value; if (result != null) { From a94e261bf164fcbf9be4055a2454bd8c1e79f257 Mon Sep 17 00:00:00 2001 From: JKorf Date: Thu, 8 Oct 2020 09:39:23 +0200 Subject: [PATCH 10/22] Updated version --- CryptoExchange.Net/CryptoExchange.Net.csproj | 4 ++-- README.md | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CryptoExchange.Net/CryptoExchange.Net.csproj b/CryptoExchange.Net/CryptoExchange.Net.csproj index d20579e..e9c55e5 100644 --- a/CryptoExchange.Net/CryptoExchange.Net.csproj +++ b/CryptoExchange.Net/CryptoExchange.Net.csproj @@ -6,12 +6,12 @@ CryptoExchange.Net JKorf A base package for implementing cryptocurrency exchange API's - 3.0.15 + 3.1.0 false https://github.com/JKorf/CryptoExchange.Net en true - 3.0.15 - Changed default ShouldCheckObjects to false to prevent spam in logging + 3.1.0 - Added CallResult without type parameter for calls which don't return data, Added GetErrorOrResult method on CallResult to support proper nullability checking, Fix for reading credentials from file, Fix for setting custom base addresses in clients enable 8.0 MIT diff --git a/README.md b/README.md index d2e597a..49e2a75 100644 --- a/README.md +++ b/README.md @@ -199,6 +199,12 @@ The order book will automatically reconnect when the connection is lost and resy To stop synchronizing an order book use the `Stop` method. ## Release notes +* Version 3.1.0 - 08 Oct 2020 + * Added CallResult without type parameter for calls which don't return data + * Added GetErrorOrResult method on CallResult to support proper nullability checking + * Fix for reading credentials from file + * Fix for setting custom base addresses in clients + * Version 3.0.15 - 06 Oct 2020 * Changed default ShouldCheckObjects to false to prevent spam in logging From 0352bb6f0670be9cadceb84e81a78b6e36a74ac6 Mon Sep 17 00:00:00 2001 From: Jkorf Date: Wed, 21 Oct 2020 10:49:32 +0200 Subject: [PATCH 11/22] Added assembly version --- CryptoExchange.Net/CryptoExchange.Net.csproj | 1 + CryptoExchange.Net/CryptoExchange.Net.xml | 145 +++++++++++++++++++ 2 files changed, 146 insertions(+) diff --git a/CryptoExchange.Net/CryptoExchange.Net.csproj b/CryptoExchange.Net/CryptoExchange.Net.csproj index e9c55e5..120091e 100644 --- a/CryptoExchange.Net/CryptoExchange.Net.csproj +++ b/CryptoExchange.Net/CryptoExchange.Net.csproj @@ -7,6 +7,7 @@ JKorf A base package for implementing cryptocurrency exchange API's 3.1.0 + 3.1.0 false https://github.com/JKorf/CryptoExchange.Net en diff --git a/CryptoExchange.Net/CryptoExchange.Net.xml b/CryptoExchange.Net/CryptoExchange.Net.xml index 3e09b10..9e81788 100644 --- a/CryptoExchange.Net/CryptoExchange.Net.xml +++ b/CryptoExchange.Net/CryptoExchange.Net.xml @@ -3052,3 +3052,148 @@ +System.Diagnostics.CodeAnalysis.AllowNullAttribute"> + + Specifies that is allowed as an input even if the + corresponding type disallows it. + + + + + Initializes a new instance of the class. + + + + + Specifies that is disallowed as an input even if the + corresponding type allows it. + + + + + Initializes a new instance of the class. + + + + + Specifies that a method that will never return under any circumstance. + + + + + Initializes a new instance of the class. + + + + + Specifies that the method will not return if the associated + parameter is passed the specified value. + + + + + Gets the condition parameter value. + Code after the method is considered unreachable by diagnostics if the argument + to the associated parameter matches this value. + + + + + Initializes a new instance of the + class with the specified parameter value. + + + The condition parameter value. + Code after the method is considered unreachable by diagnostics if the argument + to the associated parameter matches this value. + + + + + Specifies that an output may be even if the + corresponding type disallows it. + + + + + Initializes a new instance of the class. + + + + + Specifies that when a method returns , + the parameter may be even if the corresponding type disallows it. + + + + + Gets the return value condition. + If the method returns this value, the associated parameter may be . + + + + + Initializes the attribute with the specified return value condition. + + + The return value condition. + If the method returns this value, the associated parameter may be . + + + + + Specifies that an output is not even if the + corresponding type allows it. + + + + + Initializes a new instance of the class. + + + + + Specifies that the output will be non- if the + named parameter is non-. + + + + + Gets the associated parameter name. + The output will be non- if the argument to the + parameter specified is non-. + + + + + Initializes the attribute with the associated parameter name. + + + The associated parameter name. + The output will be non- if the argument to the + parameter specified is non-. + + + + + Specifies that when a method returns , + the parameter will not be even if the corresponding type allows it. + + + + + Gets the return value condition. + If the method returns this value, the associated parameter will not be . + + + + + Initializes the attribute with the specified return value condition. + + + The return value condition. + If the method returns this value, the associated parameter will not be . + + + + From 1e0ce2c776dbe831a632043a075402703f835923 Mon Sep 17 00:00:00 2001 From: Jan Korf Date: Wed, 21 Oct 2020 14:21:05 +0200 Subject: [PATCH 12/22] Update issue templates --- .github/ISSUE_TEMPLATE/bug_report.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..bc5d853 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,20 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: '' +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +What endpoints and subscriptions are called. + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Debug logging** +Add debug logging related to the issue. Enable Debug logging in the client options by settings LogVerbosity to Debug. From f3814e99464ad1a5b2ca222fd37f352481868f1a Mon Sep 17 00:00:00 2001 From: Jkorf Date: Mon, 16 Nov 2020 09:53:31 +0100 Subject: [PATCH 13/22] Added HitBTC ref --- CryptoExchange.Net/CryptoExchange.Net.xml | 4 +--- README.md | 4 ++++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CryptoExchange.Net/CryptoExchange.Net.xml b/CryptoExchange.Net/CryptoExchange.Net.xml index 9e81788..ab5dbad 100644 --- a/CryptoExchange.Net/CryptoExchange.Net.xml +++ b/CryptoExchange.Net/CryptoExchange.Net.xml @@ -3050,9 +3050,7 @@ - - -System.Diagnostics.CodeAnalysis.AllowNullAttribute"> + Specifies that is allowed as an input even if the corresponding type disallows it. diff --git a/README.md b/README.md index 49e2a75..93284b7 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,10 @@ Implementations from third parties
Bitmex + +
+HitBTC + From e53ca970457c71e36f8eb26bd201c0a65405a5fd Mon Sep 17 00:00:00 2001 From: Jkorf Date: Thu, 19 Nov 2020 10:43:11 +0100 Subject: [PATCH 14/22] Cleaned up errors, fix for socket combines --- CryptoExchange.Net/BaseClient.cs | 34 ++--- CryptoExchange.Net/CryptoExchange.Net.xml | 171 +++------------------- CryptoExchange.Net/Objects/Error.cs | 41 ++++-- CryptoExchange.Net/RestClient.cs | 6 +- CryptoExchange.Net/SocketClient.cs | 4 +- 5 files changed, 68 insertions(+), 188 deletions(-) diff --git a/CryptoExchange.Net/BaseClient.cs b/CryptoExchange.Net/BaseClient.cs index 166aa83..43b9a96 100644 --- a/CryptoExchange.Net/BaseClient.cs +++ b/CryptoExchange.Net/BaseClient.cs @@ -101,7 +101,7 @@ namespace CryptoExchange.Net { var info = "Empty data object received"; log.Write(LogVerbosity.Error, info); - return new CallResult(null, new DeserializeError(info)); + return new CallResult(null, new DeserializeError(info, data)); } try @@ -110,18 +110,18 @@ namespace CryptoExchange.Net } catch (JsonReaderException jre) { - var info = $"Deserialize JsonReaderException: {jre.Message}, Path: {jre.Path}, LineNumber: {jre.LineNumber}, LinePosition: {jre.LinePosition}. Data: {data}"; - return new CallResult(null, new DeserializeError(info)); + var info = $"Deserialize JsonReaderException: {jre.Message}, Path: {jre.Path}, LineNumber: {jre.LineNumber}, LinePosition: {jre.LinePosition}"; + return new CallResult(null, new DeserializeError(info, data)); } catch (JsonSerializationException jse) { - var info = $"Deserialize JsonSerializationException: {jse.Message}. Data: {data}"; - return new CallResult(null, new DeserializeError(info)); + var info = $"Deserialize JsonSerializationException: {jse.Message}"; + return new CallResult(null, new DeserializeError(info, data)); } catch (Exception ex) { - var info = $"Deserialize Unknown Exception: {(ex.InnerException?.Message ?? ex.Message)}. Data: {data}"; - return new CallResult(null, new DeserializeError(info)); + var info = $"Deserialize Unknown Exception: {(ex.InnerException?.Message ?? ex.Message)}"; + return new CallResult(null, new DeserializeError(info, data)); } } @@ -186,21 +186,21 @@ namespace CryptoExchange.Net } catch (JsonReaderException jre) { - var info = $"{(requestId != null ? $"[{requestId}] " : "")}Deserialize JsonReaderException: {jre.Message}, Path: {jre.Path}, LineNumber: {jre.LineNumber}, LinePosition: {jre.LinePosition}. Received data: {obj}"; + var info = $"{(requestId != null ? $"[{requestId}] " : "")}Deserialize JsonReaderException: {jre.Message}, Path: {jre.Path}, LineNumber: {jre.LineNumber}, LinePosition: {jre.LinePosition}"; log.Write(LogVerbosity.Error, info); - return new CallResult(default, new DeserializeError(info)); + return new CallResult(default, new DeserializeError(info, obj)); } catch (JsonSerializationException jse) { - var info = $"{(requestId != null ? $"[{requestId}] " : "")}Deserialize JsonSerializationException: {jse.Message}. Received data: {obj}"; + var info = $"{(requestId != null ? $"[{requestId}] " : "")}Deserialize JsonSerializationException: {jse.Message}"; log.Write(LogVerbosity.Error, info); - return new CallResult(default, new DeserializeError(info)); + return new CallResult(default, new DeserializeError(info, obj)); } catch (Exception ex) { - var info = $"{(requestId != null ? $"[{requestId}] " : "")}Deserialize Unknown Exception: {(ex.InnerException?.Message ?? ex.Message)}. Received data: {obj}"; + var info = $"{(requestId != null ? $"[{requestId}] " : "")}Deserialize Unknown Exception: {(ex.InnerException?.Message ?? ex.Message)}"; log.Write(LogVerbosity.Error, info); - return new CallResult(default, new DeserializeError(info)); + return new CallResult(default, new DeserializeError(info, obj)); } } @@ -211,7 +211,7 @@ namespace CryptoExchange.Net /// The stream to deserialize /// A specific serializer to use /// Id of the request - /// Milliseconds reponse time + /// Milliseconds response time /// protected async Task> Deserialize(Stream stream, JsonSerializer? serializer = null, int? requestId = null, long? elapsedMilliseconds = null) { @@ -237,7 +237,7 @@ namespace CryptoExchange.Net stream.Seek(0, SeekOrigin.Begin); var data = await ReadStream(stream).ConfigureAwait(false); log.Write(LogVerbosity.Error, $"{(requestId != null ? $"[{requestId}] " : "")}Deserialize JsonReaderException: {jre.Message}, Path: {jre.Path}, LineNumber: {jre.LineNumber}, LinePosition: {jre.LinePosition}, data: {data}"); - return new CallResult(default, new DeserializeError(data)); + return new CallResult(default, new DeserializeError($"Deserialize JsonReaderException: {jre.Message}, Path: {jre.Path}, LineNumber: {jre.LineNumber}, LinePosition: {jre.LinePosition}", data)); } catch (JsonSerializationException jse) { @@ -245,7 +245,7 @@ namespace CryptoExchange.Net stream.Seek(0, SeekOrigin.Begin); var data = await ReadStream(stream).ConfigureAwait(false); log.Write(LogVerbosity.Error, $"{(requestId != null ? $"[{requestId}] " : "")}Deserialize JsonSerializationException: {jse.Message}, data: {data}"); - return new CallResult(default, new DeserializeError(data)); + return new CallResult(default, new DeserializeError($"Deserialize JsonSerializationException: {jse.Message}", data)); } catch (Exception ex) { @@ -253,7 +253,7 @@ namespace CryptoExchange.Net stream.Seek(0, SeekOrigin.Begin); var data = await ReadStream(stream).ConfigureAwait(false); log.Write(LogVerbosity.Error, $"{(requestId != null ? $"[{requestId}] " : "")}Deserialize Unknown Exception: {(ex.InnerException?.Message ?? ex.Message)}, data: {data}"); - return new CallResult(default, new DeserializeError(data)); + return new CallResult(default, new DeserializeError($"Deserialize Unknown Exception: {(ex.InnerException?.Message ?? ex.Message)}", data)); } } diff --git a/CryptoExchange.Net/CryptoExchange.Net.xml b/CryptoExchange.Net/CryptoExchange.Net.xml index ab5dbad..2a08992 100644 --- a/CryptoExchange.Net/CryptoExchange.Net.xml +++ b/CryptoExchange.Net/CryptoExchange.Net.xml @@ -294,7 +294,7 @@ The stream to deserialize A specific serializer to use Id of the request - Milliseconds reponse time + Milliseconds response time @@ -1465,20 +1465,20 @@ - The error code + The error code from the server - The message for the error that occured + The message for the error that occurred - Optional data for the error + The data which caused the error - + ctor @@ -1537,10 +1537,19 @@ Web error returned by the server
- + ctor + + + + + + ctor + + + @@ -1548,18 +1557,19 @@ Error while deserializing data
- + ctor - Deserializing data + The error message + The data which caused the error Unknown error - + ctor @@ -3050,148 +3060,5 @@ - - - Specifies that is allowed as an input even if the - corresponding type disallows it. - - - - - Initializes a new instance of the class. - - - - - Specifies that is disallowed as an input even if the - corresponding type allows it. - - - - - Initializes a new instance of the class. - - - - - Specifies that a method that will never return under any circumstance. - - - - - Initializes a new instance of the class. - - - - - Specifies that the method will not return if the associated - parameter is passed the specified value. - - - - - Gets the condition parameter value. - Code after the method is considered unreachable by diagnostics if the argument - to the associated parameter matches this value. - - - - - Initializes a new instance of the - class with the specified parameter value. - - - The condition parameter value. - Code after the method is considered unreachable by diagnostics if the argument - to the associated parameter matches this value. - - - - - Specifies that an output may be even if the - corresponding type disallows it. - - - - - Initializes a new instance of the class. - - - - - Specifies that when a method returns , - the parameter may be even if the corresponding type disallows it. - - - - - Gets the return value condition. - If the method returns this value, the associated parameter may be . - - - - - Initializes the attribute with the specified return value condition. - - - The return value condition. - If the method returns this value, the associated parameter may be . - - - - - Specifies that an output is not even if the - corresponding type allows it. - - - - - Initializes a new instance of the class. - - - - - Specifies that the output will be non- if the - named parameter is non-. - - - - - Gets the associated parameter name. - The output will be non- if the argument to the - parameter specified is non-. - - - - - Initializes the attribute with the associated parameter name. - - - The associated parameter name. - The output will be non- if the argument to the - parameter specified is non-. - - - - - Specifies that when a method returns , - the parameter will not be even if the corresponding type allows it. - - - - - Gets the return value condition. - If the method returns this value, the associated parameter will not be . - - - - - Initializes the attribute with the specified return value condition. - - - The return value condition. - If the method returns this value, the associated parameter will not be . - - diff --git a/CryptoExchange.Net/Objects/Error.cs b/CryptoExchange.Net/Objects/Error.cs index 0a4b838..7d37369 100644 --- a/CryptoExchange.Net/Objects/Error.cs +++ b/CryptoExchange.Net/Objects/Error.cs @@ -6,16 +6,17 @@ public abstract class Error { /// - /// The error code + /// The error code from the server /// - public int Code { get; set; } + public int? Code { get; set; } + /// - /// The message for the error that occured + /// The message for the error that occurred /// public string Message { get; set; } /// - /// Optional data for the error + /// The data which caused the error /// public object? Data { get; set; } @@ -25,7 +26,7 @@ /// /// /// - protected Error(int code, string message, object? data) + protected Error(int? code, string message, object? data) { Code = code; Message = message; @@ -50,7 +51,7 @@ /// /// ctor /// - public CantConnectError() : base(1, "Can't connect to the server", null) { } + public CantConnectError() : base(null, "Can't connect to the server", null) { } } /// @@ -61,7 +62,7 @@ /// /// ctor /// - public NoApiCredentialsError() : base(2, "No credentials provided for private endpoint", null) { } + public NoApiCredentialsError() : base(null, "No credentials provided for private endpoint", null) { } } /// @@ -74,7 +75,7 @@ /// /// /// - public ServerError(string message, object? data = null) : base(3, "Server error: " + message, data) { } + public ServerError(string message, object? data = null) : base(null, message, data) { } /// /// ctor @@ -95,8 +96,17 @@ /// /// ctor /// + /// /// - public WebError(object? data) : base(4, "Web error", data) { } + public WebError(string message, object? data = null) : base(null, message, data) { } + + /// + /// ctor + /// + /// + /// + /// + public WebError(int code, string message, object? data = null) : base(code, message, data) { } } /// @@ -107,8 +117,9 @@ /// /// ctor /// - /// Deserializing data - public DeserializeError(object? data) : base(5, "Error deserializing data", data) { } + /// The error message + /// The data which caused the error + public DeserializeError(string message, object? data) : base(null, message, data) { } } /// @@ -120,7 +131,7 @@ /// ctor /// /// Error data - public UnknownError(object? data = null) : base(6, "Unknown error occured", data) { } + public UnknownError(string message, object? data = null) : base(null, message, data) { } } /// @@ -132,7 +143,7 @@ /// ctor /// /// - public ArgumentError(string message) : base(7, "Invalid parameter: " + message, null) { } + public ArgumentError(string message) : base(null, "Invalid parameter: " + message, null) { } } /// @@ -144,7 +155,7 @@ /// ctor /// /// - public RateLimitError(string message) : base(8, "Rate limit exceeded: " + message, null) { } + public RateLimitError(string message) : base(null, "Rate limit exceeded: " + message, null) { } } /// @@ -155,6 +166,6 @@ /// /// ctor /// - public CancellationRequestedError() : base(9, "Cancellation requested", null) { } + public CancellationRequestedError() : base(null, "Cancellation requested", null) { } } } diff --git a/CryptoExchange.Net/RestClient.cs b/CryptoExchange.Net/RestClient.cs index 5f5726c..8711d64 100644 --- a/CryptoExchange.Net/RestClient.cs +++ b/CryptoExchange.Net/RestClient.cs @@ -232,7 +232,7 @@ namespace CryptoExchange.Net var parseResult = ValidateJson(data); if (!parseResult.Success) - return WebCallResult.CreateErrorResult(response.StatusCode, response.ResponseHeaders, new ServerError(data)); + return WebCallResult.CreateErrorResult(response.StatusCode, response.ResponseHeaders, parseResult.Error!); var error = await TryParseError(parseResult.Data); if (error != null) return WebCallResult.CreateErrorResult(response.StatusCode, response.ResponseHeaders, error); @@ -257,7 +257,9 @@ namespace CryptoExchange.Net responseStream.Close(); response.Close(); var parseResult = ValidateJson(data); - return new WebCallResult(statusCode, headers, default, parseResult.Success ? ParseErrorResponse(parseResult.Data) : new ServerError(data)); + var error = parseResult.Success ? ParseErrorResponse(parseResult.Data) : parseResult.Error!; + error.Code = (int)response.StatusCode; + return new WebCallResult(statusCode, headers, default, error); } } catch (HttpRequestException requestException) diff --git a/CryptoExchange.Net/SocketClient.cs b/CryptoExchange.Net/SocketClient.cs index 5632b94..8475263 100644 --- a/CryptoExchange.Net/SocketClient.cs +++ b/CryptoExchange.Net/SocketClient.cs @@ -294,7 +294,7 @@ namespace CryptoExchange.Net var connectResult = await ConnectSocket(socket).ConfigureAwait(false); if (!connectResult) - return new CallResult(false, new CantConnectError()); + return new CallResult(false, connectResult.Error); if (!authenticated || socket.Authenticated) return new CallResult(true, null); @@ -427,7 +427,7 @@ namespace CryptoExchange.Net /// protected virtual SocketConnection GetWebsocket(string address, bool authenticated) { - var socketResult = sockets.Where(s => s.Value.Socket.Url == address.TrimEnd('/') + var socketResult = sockets.Where(s => s.Value.Socket.Url.TrimEnd('/') == address.TrimEnd('/') && (s.Value.Authenticated == authenticated || !authenticated) && s.Value.Connected).OrderBy(s => s.Value.HandlerCount).FirstOrDefault(); var result = socketResult.Equals(default(KeyValuePair)) ? null : socketResult.Value; if (result != null) From a750be6a692a78b28bc0230a1e0835b1902511ec Mon Sep 17 00:00:00 2001 From: Jan Korf Date: Thu, 19 Nov 2020 10:52:56 +0100 Subject: [PATCH 15/22] Create FUNDING.yml --- .github/FUNDING.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..852336e --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +github: JKorf From 5451d3123fa83d3b1d01b1cab86757bc9e6af957 Mon Sep 17 00:00:00 2001 From: Jkorf Date: Thu, 19 Nov 2020 11:53:55 +0100 Subject: [PATCH 16/22] Fixed some warnings --- CryptoExchange.Net/CryptoExchange.Net.xml | 1 + CryptoExchange.Net/Objects/CallResult.cs | 2 ++ CryptoExchange.Net/Objects/Error.cs | 1 + CryptoExchange.Net/Objects/Options.cs | 2 ++ CryptoExchange.Net/OrderBook/SymbolOrderBook.cs | 4 ++-- 5 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CryptoExchange.Net/CryptoExchange.Net.xml b/CryptoExchange.Net/CryptoExchange.Net.xml index 2a08992..8f96bdc 100644 --- a/CryptoExchange.Net/CryptoExchange.Net.xml +++ b/CryptoExchange.Net/CryptoExchange.Net.xml @@ -1573,6 +1573,7 @@ ctor + Error message Error data diff --git a/CryptoExchange.Net/Objects/CallResult.cs b/CryptoExchange.Net/Objects/CallResult.cs index f3be273..6a13492 100644 --- a/CryptoExchange.Net/Objects/CallResult.cs +++ b/CryptoExchange.Net/Objects/CallResult.cs @@ -65,7 +65,9 @@ namespace CryptoExchange.Net.Objects /// public CallResult([AllowNull]T data, Error? error): base(error) { +#pragma warning disable 8601 Data = data; +#pragma warning disable 8601 } /// diff --git a/CryptoExchange.Net/Objects/Error.cs b/CryptoExchange.Net/Objects/Error.cs index 7d37369..614ee2c 100644 --- a/CryptoExchange.Net/Objects/Error.cs +++ b/CryptoExchange.Net/Objects/Error.cs @@ -130,6 +130,7 @@ /// /// ctor /// + /// Error message /// Error data public UnknownError(string message, object? data = null) : base(null, message, data) { } } diff --git a/CryptoExchange.Net/Objects/Options.cs b/CryptoExchange.Net/Objects/Options.cs index ee8f2ae..3df0038 100644 --- a/CryptoExchange.Net/Objects/Options.cs +++ b/CryptoExchange.Net/Objects/Options.cs @@ -112,7 +112,9 @@ namespace CryptoExchange.Net.Objects /// ctor /// /// +#pragma warning disable 8618 public ClientOptions(string baseAddress) +#pragma warning restore 8618 { BaseAddress = baseAddress; } diff --git a/CryptoExchange.Net/OrderBook/SymbolOrderBook.cs b/CryptoExchange.Net/OrderBook/SymbolOrderBook.cs index c0e8bbf..729c68c 100644 --- a/CryptoExchange.Net/OrderBook/SymbolOrderBook.cs +++ b/CryptoExchange.Net/OrderBook/SymbolOrderBook.cs @@ -39,8 +39,8 @@ namespace CryptoExchange.Net.OrderBook private readonly bool strictLevels; private Task? _processTask; - private AutoResetEvent _queueEvent; - private ConcurrentQueue _processQueue; + private readonly AutoResetEvent _queueEvent; + private readonly ConcurrentQueue _processQueue; /// /// Order book implementation id From 64bb8a2edf6332c90baee216f17a85a249540086 Mon Sep 17 00:00:00 2001 From: Jkorf Date: Thu, 19 Nov 2020 11:58:39 +0100 Subject: [PATCH 17/22] Updated version --- CryptoExchange.Net/CryptoExchange.Net.csproj | 6 +++--- README.md | 4 ++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/CryptoExchange.Net/CryptoExchange.Net.csproj b/CryptoExchange.Net/CryptoExchange.Net.csproj index 120091e..1db6b63 100644 --- a/CryptoExchange.Net/CryptoExchange.Net.csproj +++ b/CryptoExchange.Net/CryptoExchange.Net.csproj @@ -6,13 +6,13 @@ CryptoExchange.Net JKorf A base package for implementing cryptocurrency exchange API's - 3.1.0 - 3.1.0 + 3.2.0 + 3.2.0 false https://github.com/JKorf/CryptoExchange.Net en true - 3.1.0 - Added CallResult without type parameter for calls which don't return data, Added GetErrorOrResult method on CallResult to support proper nullability checking, Fix for reading credentials from file, Fix for setting custom base addresses in clients + 3.2.0 - Fix for multiple socket subscriptions re-using the same socket connection, Updated errors enable 8.0 MIT diff --git a/README.md b/README.md index 93284b7..4b9763b 100644 --- a/README.md +++ b/README.md @@ -203,6 +203,10 @@ The order book will automatically reconnect when the connection is lost and resy To stop synchronizing an order book use the `Stop` method. ## Release notes +* Version 3.2.0 - 19 nov 2020 + * Fix for multiple socket subscriptions re-using the same socket connection + * Updated errors + * Version 3.1.0 - 08 Oct 2020 * Added CallResult without type parameter for calls which don't return data * Added GetErrorOrResult method on CallResult to support proper nullability checking From c5344baf3ae980874c99c416d21495b82bf86941 Mon Sep 17 00:00:00 2001 From: Jkorf Date: Thu, 19 Nov 2020 12:02:54 +0100 Subject: [PATCH 18/22] Fixed error code setting --- CryptoExchange.Net/RestClient.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CryptoExchange.Net/RestClient.cs b/CryptoExchange.Net/RestClient.cs index 8711d64..b31d7b8 100644 --- a/CryptoExchange.Net/RestClient.cs +++ b/CryptoExchange.Net/RestClient.cs @@ -258,7 +258,8 @@ namespace CryptoExchange.Net response.Close(); var parseResult = ValidateJson(data); var error = parseResult.Success ? ParseErrorResponse(parseResult.Data) : parseResult.Error!; - error.Code = (int)response.StatusCode; + if(error.Code == null || error.Code == 0) + error.Code = (int)response.StatusCode; return new WebCallResult(statusCode, headers, default, error); } } From 3b6463015aec589e80e0758eaf1d0823f5f6af62 Mon Sep 17 00:00:00 2001 From: Jkorf Date: Thu, 19 Nov 2020 12:03:30 +0100 Subject: [PATCH 19/22] Updated version --- CryptoExchange.Net/CryptoExchange.Net.csproj | 4 ++-- README.md | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CryptoExchange.Net/CryptoExchange.Net.csproj b/CryptoExchange.Net/CryptoExchange.Net.csproj index 1db6b63..e2f8876 100644 --- a/CryptoExchange.Net/CryptoExchange.Net.csproj +++ b/CryptoExchange.Net/CryptoExchange.Net.csproj @@ -6,13 +6,13 @@ CryptoExchange.Net JKorf A base package for implementing cryptocurrency exchange API's - 3.2.0 + 3.2.1 3.2.0 false https://github.com/JKorf/CryptoExchange.Net en true - 3.2.0 - Fix for multiple socket subscriptions re-using the same socket connection, Updated errors + 3.2.1 - Fixed error code parsing enable 8.0 MIT diff --git a/README.md b/README.md index 4b9763b..30d957b 100644 --- a/README.md +++ b/README.md @@ -203,6 +203,9 @@ The order book will automatically reconnect when the connection is lost and resy To stop synchronizing an order book use the `Stop` method. ## Release notes +* Version 3.2.1 - 19 nov 2020 + * Fixed error code parsing + * Version 3.2.0 - 19 nov 2020 * Fix for multiple socket subscriptions re-using the same socket connection * Updated errors From df9d09630ae796545c8d8e40868e880f917f39a5 Mon Sep 17 00:00:00 2001 From: Jkorf Date: Thu, 10 Dec 2020 14:05:34 +0100 Subject: [PATCH 20/22] Added name to clients, added common interfaces --- .../TestImplementations/TestBaseClient.cs | 4 +- .../TestImplementations/TestRestClient.cs | 4 +- .../TestImplementations/TestSocketClient.cs | 2 +- CryptoExchange.Net/BaseClient.cs | 10 +- CryptoExchange.Net/CryptoExchange.Net.csproj | 4 +- CryptoExchange.Net/CryptoExchange.Net.xml | 277 +++++++++++++++++- .../ExchangeInterfaces/ICommonTrade.cs | 33 +++ .../ExchangeInterfaces/IExchangeClient.cs | 133 +++++++++ .../ExchangeInterfaces/IKline.cs | 29 ++ .../ExchangeInterfaces/IOrder.cs | 41 +++ .../ExchangeInterfaces/IOrderBook.cs | 22 ++ .../ExchangeInterfaces/IPlacedOrder.cs | 17 ++ .../ExchangeInterfaces/IRecentTrade.cs | 25 ++ .../ExchangeInterfaces/ISymbol.cs | 21 ++ .../ExchangeInterfaces/ITicker.cs | 29 ++ CryptoExchange.Net/Interfaces/IRestClient.cs | 5 + CryptoExchange.Net/Logging/Log.cs | 10 +- CryptoExchange.Net/Objects/CallResult.cs | 23 ++ .../OrderBook/SymbolOrderBook.cs | 2 +- CryptoExchange.Net/RestClient.cs | 3 +- CryptoExchange.Net/SocketClient.cs | 3 +- 21 files changed, 679 insertions(+), 18 deletions(-) create mode 100644 CryptoExchange.Net/ExchangeInterfaces/ICommonTrade.cs create mode 100644 CryptoExchange.Net/ExchangeInterfaces/IExchangeClient.cs create mode 100644 CryptoExchange.Net/ExchangeInterfaces/IKline.cs create mode 100644 CryptoExchange.Net/ExchangeInterfaces/IOrder.cs create mode 100644 CryptoExchange.Net/ExchangeInterfaces/IOrderBook.cs create mode 100644 CryptoExchange.Net/ExchangeInterfaces/IPlacedOrder.cs create mode 100644 CryptoExchange.Net/ExchangeInterfaces/IRecentTrade.cs create mode 100644 CryptoExchange.Net/ExchangeInterfaces/ISymbol.cs create mode 100644 CryptoExchange.Net/ExchangeInterfaces/ITicker.cs diff --git a/CryptoExchange.Net.UnitTests/TestImplementations/TestBaseClient.cs b/CryptoExchange.Net.UnitTests/TestImplementations/TestBaseClient.cs index d9e2e91..df87c64 100644 --- a/CryptoExchange.Net.UnitTests/TestImplementations/TestBaseClient.cs +++ b/CryptoExchange.Net.UnitTests/TestImplementations/TestBaseClient.cs @@ -9,11 +9,11 @@ namespace CryptoExchange.Net.UnitTests { public class TestBaseClient: BaseClient { - public TestBaseClient(): base(new RestClientOptions("http://testurl.url"), null) + public TestBaseClient(): base("Test", new RestClientOptions("http://testurl.url"), null) { } - public TestBaseClient(RestClientOptions exchangeOptions) : base(exchangeOptions, exchangeOptions.ApiCredentials == null ? null : new TestAuthProvider(exchangeOptions.ApiCredentials)) + public TestBaseClient(RestClientOptions exchangeOptions) : base("Test", exchangeOptions, exchangeOptions.ApiCredentials == null ? null : new TestAuthProvider(exchangeOptions.ApiCredentials)) { } diff --git a/CryptoExchange.Net.UnitTests/TestImplementations/TestRestClient.cs b/CryptoExchange.Net.UnitTests/TestImplementations/TestRestClient.cs index 7189508..f38aa0c 100644 --- a/CryptoExchange.Net.UnitTests/TestImplementations/TestRestClient.cs +++ b/CryptoExchange.Net.UnitTests/TestImplementations/TestRestClient.cs @@ -16,12 +16,12 @@ namespace CryptoExchange.Net.UnitTests.TestImplementations { public class TestRestClient: RestClient { - public TestRestClient() : base(new RestClientOptions("http://testurl.url"), null) + public TestRestClient() : base("Test", new RestClientOptions("http://testurl.url"), null) { RequestFactory = new Mock().Object; } - public TestRestClient(RestClientOptions exchangeOptions) : base(exchangeOptions, exchangeOptions.ApiCredentials == null ? null : new TestAuthProvider(exchangeOptions.ApiCredentials)) + public TestRestClient(RestClientOptions exchangeOptions) : base("Test", exchangeOptions, exchangeOptions.ApiCredentials == null ? null : new TestAuthProvider(exchangeOptions.ApiCredentials)) { RequestFactory = new Mock().Object; } diff --git a/CryptoExchange.Net.UnitTests/TestImplementations/TestSocketClient.cs b/CryptoExchange.Net.UnitTests/TestImplementations/TestSocketClient.cs index 43f18b9..886d948 100644 --- a/CryptoExchange.Net.UnitTests/TestImplementations/TestSocketClient.cs +++ b/CryptoExchange.Net.UnitTests/TestImplementations/TestSocketClient.cs @@ -15,7 +15,7 @@ namespace CryptoExchange.Net.UnitTests.TestImplementations { } - public TestSocketClient(SocketClientOptions exchangeOptions) : base(exchangeOptions, exchangeOptions.ApiCredentials == null ? null : new TestAuthProvider(exchangeOptions.ApiCredentials)) + public TestSocketClient(SocketClientOptions exchangeOptions) : base("test", exchangeOptions, exchangeOptions.ApiCredentials == null ? null : new TestAuthProvider(exchangeOptions.ApiCredentials)) { SocketFactory = new Mock().Object; Mock.Get(SocketFactory).Setup(f => f.CreateWebsocket(It.IsAny(), It.IsAny())).Returns(new TestSocket()); diff --git a/CryptoExchange.Net/BaseClient.cs b/CryptoExchange.Net/BaseClient.cs index 43b9a96..a6749f1 100644 --- a/CryptoExchange.Net/BaseClient.cs +++ b/CryptoExchange.Net/BaseClient.cs @@ -25,6 +25,10 @@ namespace CryptoExchange.Net /// public string BaseAddress { get; } /// + /// The name of the client + /// + public string ClientName { get; } + /// /// The log object /// protected internal Log log; @@ -64,15 +68,17 @@ namespace CryptoExchange.Net /// /// ctor /// + /// /// /// - protected BaseClient(ClientOptions options, AuthenticationProvider? authenticationProvider) + protected BaseClient(string clientName, ClientOptions options, AuthenticationProvider? authenticationProvider) { - log = new Log(); + log = new Log(clientName); authProvider = authenticationProvider; log.UpdateWriters(options.LogWriters); log.Level = options.LogVerbosity; + ClientName = clientName; BaseAddress = options.BaseAddress; apiProxy = options.Proxy; diff --git a/CryptoExchange.Net/CryptoExchange.Net.csproj b/CryptoExchange.Net/CryptoExchange.Net.csproj index e2f8876..ecfb92c 100644 --- a/CryptoExchange.Net/CryptoExchange.Net.csproj +++ b/CryptoExchange.Net/CryptoExchange.Net.csproj @@ -1,4 +1,4 @@ - + netstandard2.0;netstandard2.1 @@ -21,7 +21,7 @@ CryptoExchange.Net.xml - + \ No newline at end of file diff --git a/CryptoExchange.Net/CryptoExchange.Net.xml b/CryptoExchange.Net/CryptoExchange.Net.xml index 8f96bdc..f67ab25 100644 --- a/CryptoExchange.Net/CryptoExchange.Net.xml +++ b/CryptoExchange.Net/CryptoExchange.Net.xml @@ -209,6 +209,11 @@ The address of the client + + + The name of the client + + The log object @@ -244,10 +249,11 @@ Last is used - + ctor + @@ -435,6 +441,105 @@ + + + Shared interface for exchange wrappers based on the CryptoExchange.Net package + + + + + Get the symbol name basset on a base and quote asset + + + + + + + + Get a list of symbols for the exchange + + + + + + Get a list of tickers for the exchange + + + + + + Get a list of candles for a given symbol on the exchange + + The symbol to retrieve the candles for + The timespan to retrieve the candles for. The supported value are dependent on the exchange + + + + + Get the order book for a symbol + + The symbol to get the book for + + + + + The recent trades for a symbol + + The symbol to get the trades for + + + + + Place an order + + The symbol the order is for + The side of the order + The type of the order + The quantity of the order + The price of the order, only for limit orders + [Optional] The account id to place the order on, required for some exchanges + The id of the resulting order + + + + Get an order by id + + The id + [Optional] The symbol the order is on, required for some exchanges + + + + + Get trades for an order by id + + The id + [Optional] The symbol the order is on, required for some exchanges + + + + + Get a list of open orders + + [Optional] The symbol to get open orders for, required for some exchanges. If the symbol is not required for the call, + the result will NOT be filtered by this + + + + + Get a list of closed orders + + [Optional] The symbol to get closed orders for, required for some exchanges. If the symbol is not required for the call, + the result will NOT be filtered by this + + + + + Cancel an order by id + + The id + [Optional] The symbol the order is on, required for some exchanges + + Helper methods @@ -712,6 +817,11 @@ The base address of the API + + + Client name + + Adds a rate limiter to the client. There are 2 choices, the and the . @@ -1065,7 +1175,12 @@ The verbosity of the logging - + + + Client name + + + ctor @@ -1304,6 +1419,15 @@ + + + Create an error result + + + + + + The result of a request @@ -2259,10 +2383,11 @@ Total requests made - + ctor + @@ -2423,10 +2548,11 @@ If false; data which is a response to a query won't get forwarded to subscriptions as well - + Create a socket client + Client name Client options Authentication provider @@ -3061,5 +3187,148 @@ + + + Specifies that is allowed as an input even if the + corresponding type disallows it. + + + + + Initializes a new instance of the class. + + + + + Specifies that is disallowed as an input even if the + corresponding type allows it. + + + + + Initializes a new instance of the class. + + + + + Specifies that a method that will never return under any circumstance. + + + + + Initializes a new instance of the class. + + + + + Specifies that the method will not return if the associated + parameter is passed the specified value. + + + + + Gets the condition parameter value. + Code after the method is considered unreachable by diagnostics if the argument + to the associated parameter matches this value. + + + + + Initializes a new instance of the + class with the specified parameter value. + + + The condition parameter value. + Code after the method is considered unreachable by diagnostics if the argument + to the associated parameter matches this value. + + + + + Specifies that an output may be even if the + corresponding type disallows it. + + + + + Initializes a new instance of the class. + + + + + Specifies that when a method returns , + the parameter may be even if the corresponding type disallows it. + + + + + Gets the return value condition. + If the method returns this value, the associated parameter may be . + + + + + Initializes the attribute with the specified return value condition. + + + The return value condition. + If the method returns this value, the associated parameter may be . + + + + + Specifies that an output is not even if the + corresponding type allows it. + + + + + Initializes a new instance of the class. + + + + + Specifies that the output will be non- if the + named parameter is non-. + + + + + Gets the associated parameter name. + The output will be non- if the argument to the + parameter specified is non-. + + + + + Initializes the attribute with the associated parameter name. + + + The associated parameter name. + The output will be non- if the argument to the + parameter specified is non-. + + + + + Specifies that when a method returns , + the parameter will not be even if the corresponding type allows it. + + + + + Gets the return value condition. + If the method returns this value, the associated parameter will not be . + + + + + Initializes the attribute with the specified return value condition. + + + The return value condition. + If the method returns this value, the associated parameter will not be . + + diff --git a/CryptoExchange.Net/ExchangeInterfaces/ICommonTrade.cs b/CryptoExchange.Net/ExchangeInterfaces/ICommonTrade.cs new file mode 100644 index 0000000..b1a424f --- /dev/null +++ b/CryptoExchange.Net/ExchangeInterfaces/ICommonTrade.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace CryptoExchange.Net.ExchangeInterfaces +{ + /// + /// Common trade + /// + public interface ICommonTrade + { + /// + /// Id of the trade + /// + public string CommonId { get; } + /// + /// Price of the trade + /// + public decimal CommonPrice { get; } + /// + /// Quantity of the trade + /// + public decimal CommonQuantity { get; } + /// + /// Fee paid for the trade + /// + public decimal CommonFee { get; } + /// + /// The asset fee was paid in + /// + public string? CommonFeeAsset { get; } + } +} diff --git a/CryptoExchange.Net/ExchangeInterfaces/IExchangeClient.cs b/CryptoExchange.Net/ExchangeInterfaces/IExchangeClient.cs new file mode 100644 index 0000000..145f069 --- /dev/null +++ b/CryptoExchange.Net/ExchangeInterfaces/IExchangeClient.cs @@ -0,0 +1,133 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using CryptoExchange.Net.Objects; + +namespace CryptoExchange.Net.ExchangeInterfaces +{ + /// + /// Shared interface for exchange wrappers based on the CryptoExchange.Net package + /// + public interface IExchangeClient + { + /// + /// Get the symbol name based on a base and quote asset + /// + /// + /// + /// + string GetSymbolName(string baseAsset, string quoteAsset); + + /// + /// Get a list of symbols for the exchange + /// + /// + Task>> GetSymbolsAsync(); + + /// + /// Get a list of tickers for the exchange + /// + /// + Task>> GetTickersAsync(); + + /// + /// Get a list of candles for a given symbol on the exchange + /// + /// The symbol to retrieve the candles for + /// The timespan to retrieve the candles for. The supported value are dependent on the exchange + /// + Task>> GetKlinesAsync(string symbol, TimeSpan timespan); + /// + /// Get the order book for a symbol + /// + /// The symbol to get the book for + /// + Task> GetOrderBookAsync(string symbol); + /// + /// The recent trades for a symbol + /// + /// The symbol to get the trades for + /// + Task>> GetRecentTradesAsync(string symbol); + + /// + /// Place an order + /// + /// The symbol the order is for + /// The side of the order + /// The type of the order + /// The quantity of the order + /// The price of the order, only for limit orders + /// [Optional] The account id to place the order on, required for some exchanges, ignored otherwise + /// The id of the resulting order + Task> PlaceOrderAsync(string symbol, OrderSide side, OrderType type, decimal quantity, decimal? price = null, string? accountId = null); + /// + /// Get an order by id + /// + /// The id + /// [Optional] The symbol the order is on, required for some exchanges, ignored otherwise + /// + Task> GetOrderAsync(string orderId, string? symbol = null); + /// + /// Get trades for an order by id + /// + /// The id + /// [Optional] The symbol the order is on, required for some exchanges, ignored otherwise + /// + Task>> GetTradesAsync(string orderId, string? symbol = null); + /// + /// Get a list of open orders + /// + /// [Optional] The symbol to get open orders for, required for some exchanges, ignored otherwise + /// + Task>> GetOpenOrdersAsync(string? symbol); + + /// + /// Get a list of closed orders + /// + /// [Optional] The symbol to get closed orders for, required for some exchanges, ignored otherwise + /// + Task>> GetClosedOrdersAsync(string? symbol); + /// + /// Cancel an order by id + /// + /// The id + /// [Optional] The symbol the order is on, required for some exchanges, ignored otherwise + /// + Task> CancelOrderAsync(string orderId, string? symbol); + + /// + /// Common order id + /// + public enum OrderType + { + /// + /// Limit type + /// + Limit, + /// + /// Market type + /// + Market, + /// + /// Other order type + /// + Other + } + + /// + /// Common order side + /// + public enum OrderSide + { + /// + /// Buy order + /// + Buy, + /// + /// Sell order + /// + Sell + } + } +} diff --git a/CryptoExchange.Net/ExchangeInterfaces/IKline.cs b/CryptoExchange.Net/ExchangeInterfaces/IKline.cs new file mode 100644 index 0000000..7fd74fc --- /dev/null +++ b/CryptoExchange.Net/ExchangeInterfaces/IKline.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace CryptoExchange.Net.ExchangeInterfaces +{ + /// + /// Common kline + /// + public interface ICommonKline + { + /// + /// High price for this kline + /// + decimal CommonHigh { get; } + /// + /// Low price for this kline + /// + decimal CommonLow { get; } + /// + /// Open price for this kline + /// + decimal CommonOpen { get; } + /// + /// Close price for this kline + /// + decimal CommonClose { get; } + } +} diff --git a/CryptoExchange.Net/ExchangeInterfaces/IOrder.cs b/CryptoExchange.Net/ExchangeInterfaces/IOrder.cs new file mode 100644 index 0000000..cd93a5f --- /dev/null +++ b/CryptoExchange.Net/ExchangeInterfaces/IOrder.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace CryptoExchange.Net.ExchangeInterfaces +{ + /// + /// Common order + /// + public interface ICommonOrder: ICommonOrderId + { + /// + /// Symbol of the order + /// + public string CommonSymbol { get; } + /// + /// Price of the order + /// + public decimal CommonPrice { get; } + /// + /// Quantity of the order + /// + public decimal CommonQuantity { get; } + /// + /// Status of the order + /// + public string CommonStatus { get; } + /// + /// Whether the order is active + /// + public bool IsActive { get; } + /// + /// Side of the order + /// + public IExchangeClient.OrderSide CommonSide { get; } + /// + /// Type of the order + /// + public IExchangeClient.OrderType CommonType { get; } + } +} diff --git a/CryptoExchange.Net/ExchangeInterfaces/IOrderBook.cs b/CryptoExchange.Net/ExchangeInterfaces/IOrderBook.cs new file mode 100644 index 0000000..d614110 --- /dev/null +++ b/CryptoExchange.Net/ExchangeInterfaces/IOrderBook.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Text; +using CryptoExchange.Net.Interfaces; + +namespace CryptoExchange.Net.ExchangeInterfaces +{ + /// + /// Common order book + /// + public interface ICommonOrderBook + { + /// + /// Bids + /// + IEnumerable CommonBids { get; } + /// + /// Asks + /// + IEnumerable CommonAsks { get; } + } +} diff --git a/CryptoExchange.Net/ExchangeInterfaces/IPlacedOrder.cs b/CryptoExchange.Net/ExchangeInterfaces/IPlacedOrder.cs new file mode 100644 index 0000000..0e66649 --- /dev/null +++ b/CryptoExchange.Net/ExchangeInterfaces/IPlacedOrder.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace CryptoExchange.Net.ExchangeInterfaces +{ + /// + /// Common order id + /// + public interface ICommonOrderId + { + /// + /// Id of the order + /// + public string CommonId { get; } + } +} diff --git a/CryptoExchange.Net/ExchangeInterfaces/IRecentTrade.cs b/CryptoExchange.Net/ExchangeInterfaces/IRecentTrade.cs new file mode 100644 index 0000000..f9b59e4 --- /dev/null +++ b/CryptoExchange.Net/ExchangeInterfaces/IRecentTrade.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace CryptoExchange.Net.ExchangeInterfaces +{ + /// + /// Recent trade + /// + public interface ICommonRecentTrade + { + /// + /// Price of the trade + /// + decimal CommonPrice { get; } + /// + /// Quantity of the trade + /// + decimal CommonQuantity { get; } + /// + /// Trade time + /// + DateTime CommonTradeTime { get; } + } +} diff --git a/CryptoExchange.Net/ExchangeInterfaces/ISymbol.cs b/CryptoExchange.Net/ExchangeInterfaces/ISymbol.cs new file mode 100644 index 0000000..2ff59a5 --- /dev/null +++ b/CryptoExchange.Net/ExchangeInterfaces/ISymbol.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace CryptoExchange.Net.ExchangeInterfaces +{ + /// + /// Common symbol + /// + public interface ICommonSymbol + { + /// + /// Symbol name + /// + public string CommonName { get; } + /// + /// Minimum trade size + /// + public decimal CommonMinimumTradeSize { get; } + } +} diff --git a/CryptoExchange.Net/ExchangeInterfaces/ITicker.cs b/CryptoExchange.Net/ExchangeInterfaces/ITicker.cs new file mode 100644 index 0000000..53979b5 --- /dev/null +++ b/CryptoExchange.Net/ExchangeInterfaces/ITicker.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace CryptoExchange.Net.ExchangeInterfaces +{ + /// + /// Common ticker + /// + public interface ICommonTicker + { + /// + /// Symbol name + /// + public string CommonSymbol { get; } + /// + /// High price + /// + public decimal CommonHigh { get; } + /// + /// Low price + /// + public decimal CommonLow { get; } + /// + /// Volume + /// + public decimal CommonVolume { get; } + } +} diff --git a/CryptoExchange.Net/Interfaces/IRestClient.cs b/CryptoExchange.Net/Interfaces/IRestClient.cs index 60d9e8b..f46f430 100644 --- a/CryptoExchange.Net/Interfaces/IRestClient.cs +++ b/CryptoExchange.Net/Interfaces/IRestClient.cs @@ -37,6 +37,11 @@ namespace CryptoExchange.Net.Interfaces /// string BaseAddress { get; } + /// + /// Client name + /// + string ClientName { get; } + /// /// Adds a rate limiter to the client. There are 2 choices, the and the . /// diff --git a/CryptoExchange.Net/Logging/Log.cs b/CryptoExchange.Net/Logging/Log.cs index d04189b..f37458a 100644 --- a/CryptoExchange.Net/Logging/Log.cs +++ b/CryptoExchange.Net/Logging/Log.cs @@ -17,11 +17,17 @@ namespace CryptoExchange.Net.Logging /// public LogVerbosity Level { get; set; } = LogVerbosity.Info; + /// + /// Client name + /// + public string ClientName { get; set; } + /// /// ctor /// - public Log() + public Log(string clientName) { + ClientName = clientName; writers = new List(); } @@ -44,7 +50,7 @@ namespace CryptoExchange.Net.Logging if ((int)logType < (int)Level) return; - var logMessage = $"{DateTime.Now:yyyy/MM/dd HH:mm:ss:fff} | {logType} | {message}"; + var logMessage = $"{DateTime.Now:yyyy/MM/dd HH:mm:ss:fff} | {ClientName.PadRight(10)} | {logType} | {message}"; foreach (var writer in writers.ToList()) { try diff --git a/CryptoExchange.Net/Objects/CallResult.cs b/CryptoExchange.Net/Objects/CallResult.cs index 6a13492..23409e5 100644 --- a/CryptoExchange.Net/Objects/CallResult.cs +++ b/CryptoExchange.Net/Objects/CallResult.cs @@ -154,6 +154,18 @@ namespace CryptoExchange.Net.Objects { return new WebCallResult(code, responseHeaders, error); } + + /// + /// Create an error result + /// + /// + /// + /// + /// + public static WebCallResult CreateErrorResult(WebCallResult result) + { + return new WebCallResult(result.ResponseStatusCode, result.ResponseHeaders, result.Error); + } } /// @@ -187,6 +199,17 @@ namespace CryptoExchange.Net.Objects ResponseHeaders = responseHeaders; } + public WebCallResult(WebCallResult callResult): base(callResult.Data, callResult.Error) + { + ResponseHeaders = callResult.ResponseHeaders; + ResponseStatusCode = callResult.ResponseStatusCode; + } + + public static WebCallResult CreateFrom(WebCallResult source) where Y : T + { + return new WebCallResult(source.ResponseStatusCode, source.ResponseHeaders, (T)source.Data, source.Error); + } + /// /// Create an error result /// diff --git a/CryptoExchange.Net/OrderBook/SymbolOrderBook.cs b/CryptoExchange.Net/OrderBook/SymbolOrderBook.cs index 729c68c..4cf138c 100644 --- a/CryptoExchange.Net/OrderBook/SymbolOrderBook.cs +++ b/CryptoExchange.Net/OrderBook/SymbolOrderBook.cs @@ -208,7 +208,7 @@ namespace CryptoExchange.Net.OrderBook asks = new SortedList(); bids = new SortedList(new DescComparer()); - log = new Log { Level = options.LogVerbosity }; + log = new Log(options.OrderBookName) { Level = options.LogVerbosity }; var writers = options.LogWriters ?? new List { new DebugTextWriter() }; log.UpdateWriters(writers.ToList()); } diff --git a/CryptoExchange.Net/RestClient.cs b/CryptoExchange.Net/RestClient.cs index b31d7b8..d3372fa 100644 --- a/CryptoExchange.Net/RestClient.cs +++ b/CryptoExchange.Net/RestClient.cs @@ -76,9 +76,10 @@ namespace CryptoExchange.Net /// /// ctor /// + /// /// /// - protected RestClient(RestClientOptions exchangeOptions, AuthenticationProvider? authenticationProvider) : base(exchangeOptions, authenticationProvider) + protected RestClient(string clientName, RestClientOptions exchangeOptions, AuthenticationProvider? authenticationProvider) : base(clientName, exchangeOptions, authenticationProvider) { if (exchangeOptions == null) throw new ArgumentNullException(nameof(exchangeOptions)); diff --git a/CryptoExchange.Net/SocketClient.cs b/CryptoExchange.Net/SocketClient.cs index 8475263..0332595 100644 --- a/CryptoExchange.Net/SocketClient.cs +++ b/CryptoExchange.Net/SocketClient.cs @@ -83,9 +83,10 @@ namespace CryptoExchange.Net /// /// Create a socket client /// + /// Client name /// Client options /// Authentication provider - protected SocketClient(SocketClientOptions exchangeOptions, AuthenticationProvider? authenticationProvider): base(exchangeOptions, authenticationProvider) + protected SocketClient(string clientName, SocketClientOptions exchangeOptions, AuthenticationProvider? authenticationProvider): base(clientName, exchangeOptions, authenticationProvider) { if (exchangeOptions == null) throw new ArgumentNullException(nameof(exchangeOptions)); From dd06f48fc198a00a183d72d132e8942e8ac57bbe Mon Sep 17 00:00:00 2001 From: Jkorf Date: Thu, 10 Dec 2020 14:44:15 +0100 Subject: [PATCH 21/22] Fixed api key storing in api key rate limitter --- CryptoExchange.Net/CryptoExchange.Net.xml | 379 +++++++++++------- .../RateLimiter/RateLimiterAPIKey.cs | 23 +- 2 files changed, 248 insertions(+), 154 deletions(-) diff --git a/CryptoExchange.Net/CryptoExchange.Net.xml b/CryptoExchange.Net/CryptoExchange.Net.xml index f67ab25..148cefe 100644 --- a/CryptoExchange.Net/CryptoExchange.Net.xml +++ b/CryptoExchange.Net/CryptoExchange.Net.xml @@ -441,6 +441,36 @@ + + + Common trade + + + + + Id of the trade + + + + + Price of the trade + + + + + Quantity of the trade + + + + + Fee paid for the trade + + + + + The asset fee was paid in + + Shared interface for exchange wrappers based on the CryptoExchange.Net package @@ -448,7 +478,7 @@ - Get the symbol name basset on a base and quote asset + Get the symbol name based on a base and quote asset @@ -497,7 +527,7 @@ The type of the order The quantity of the order The price of the order, only for limit orders - [Optional] The account id to place the order on, required for some exchanges + [Optional] The account id to place the order on, required for some exchanges, ignored otherwise The id of the resulting order @@ -505,7 +535,7 @@ Get an order by id The id - [Optional] The symbol the order is on, required for some exchanges + [Optional] The symbol the order is on, required for some exchanges, ignored otherwise @@ -513,23 +543,21 @@ Get trades for an order by id The id - [Optional] The symbol the order is on, required for some exchanges + [Optional] The symbol the order is on, required for some exchanges, ignored otherwise Get a list of open orders - [Optional] The symbol to get open orders for, required for some exchanges. If the symbol is not required for the call, - the result will NOT be filtered by this + [Optional] The symbol to get open orders for, required for some exchanges, ignored otherwise Get a list of closed orders - [Optional] The symbol to get closed orders for, required for some exchanges. If the symbol is not required for the call, - the result will NOT be filtered by this + [Optional] The symbol to get closed orders for, required for some exchanges, ignored otherwise @@ -537,9 +565,194 @@ Cancel an order by id The id - [Optional] The symbol the order is on, required for some exchanges + [Optional] The symbol the order is on, required for some exchanges, ignored otherwise + + + Common order id + + + + + Limit type + + + + + Market type + + + + + Other order type + + + + + Common order side + + + + + Buy order + + + + + Sell order + + + + + Common kline + + + + + High price for this kline + + + + + Low price for this kline + + + + + Open price for this kline + + + + + Close price for this kline + + + + + Common order + + + + + Symbol of the order + + + + + Price of the order + + + + + Quantity of the order + + + + + Status of the order + + + + + Whether the order is active + + + + + Side of the order + + + + + Type of the order + + + + + Common order book + + + + + Bids + + + + + Asks + + + + + Common order id + + + + + Id of the order + + + + + Recent trade + + + + + Price of the trade + + + + + Quantity of the trade + + + + + Trade time + + + + + Common symbol + + + + + Symbol name + + + + + Minimum trade size + + + + + Common ticker + + + + + Symbol name + + + + + High price + + + + + Low price + + + + + Volume + + Helper methods @@ -2191,6 +2404,11 @@ + + + Dispose + + Limits the amount of requests per time period to a certain limit, counts the request per endpoint. @@ -3187,148 +3405,5 @@ - - - Specifies that is allowed as an input even if the - corresponding type disallows it. - - - - - Initializes a new instance of the class. - - - - - Specifies that is disallowed as an input even if the - corresponding type allows it. - - - - - Initializes a new instance of the class. - - - - - Specifies that a method that will never return under any circumstance. - - - - - Initializes a new instance of the class. - - - - - Specifies that the method will not return if the associated - parameter is passed the specified value. - - - - - Gets the condition parameter value. - Code after the method is considered unreachable by diagnostics if the argument - to the associated parameter matches this value. - - - - - Initializes a new instance of the - class with the specified parameter value. - - - The condition parameter value. - Code after the method is considered unreachable by diagnostics if the argument - to the associated parameter matches this value. - - - - - Specifies that an output may be even if the - corresponding type disallows it. - - - - - Initializes a new instance of the class. - - - - - Specifies that when a method returns , - the parameter may be even if the corresponding type disallows it. - - - - - Gets the return value condition. - If the method returns this value, the associated parameter may be . - - - - - Initializes the attribute with the specified return value condition. - - - The return value condition. - If the method returns this value, the associated parameter may be . - - - - - Specifies that an output is not even if the - corresponding type allows it. - - - - - Initializes a new instance of the class. - - - - - Specifies that the output will be non- if the - named parameter is non-. - - - - - Gets the associated parameter name. - The output will be non- if the argument to the - parameter specified is non-. - - - - - Initializes the attribute with the associated parameter name. - - - The associated parameter name. - The output will be non- if the argument to the - parameter specified is non-. - - - - - Specifies that when a method returns , - the parameter will not be even if the corresponding type allows it. - - - - - Gets the return value condition. - If the method returns this value, the associated parameter will not be . - - - - - Initializes the attribute with the specified return value condition. - - - The return value condition. - If the method returns this value, the associated parameter will not be . - - diff --git a/CryptoExchange.Net/RateLimiter/RateLimiterAPIKey.cs b/CryptoExchange.Net/RateLimiter/RateLimiterAPIKey.cs index 4bd9af3..0b2dddf 100644 --- a/CryptoExchange.Net/RateLimiter/RateLimiterAPIKey.cs +++ b/CryptoExchange.Net/RateLimiter/RateLimiterAPIKey.cs @@ -1,6 +1,8 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Security.Cryptography; +using System.Text; using System.Threading; using CryptoExchange.Net.Interfaces; using CryptoExchange.Net.Objects; @@ -10,10 +12,11 @@ namespace CryptoExchange.Net.RateLimiter /// /// Limits the amount of requests per time period to a certain limit, counts the request per API key. /// - public class RateLimiterAPIKey: IRateLimiter + public class RateLimiterAPIKey: IRateLimiter, IDisposable { internal Dictionary history = new Dictionary(); + private readonly SHA256 encryptor; private readonly int limitPerKey; private readonly TimeSpan perTimePeriod; private readonly object historyLock = new object(); @@ -26,6 +29,7 @@ namespace CryptoExchange.Net.RateLimiter public RateLimiterAPIKey(int limitPerApiKey, TimeSpan perTimePeriod) { limitPerKey = limitPerApiKey; + encryptor = SHA256.Create(); this.perTimePeriod = perTimePeriod; } @@ -35,7 +39,14 @@ namespace CryptoExchange.Net.RateLimiter if(client.authProvider?.Credentials?.Key == null) return new CallResult(0, null); - var key = client.authProvider.Credentials.Key.GetString(); + var keyBytes = encryptor.ComputeHash(Encoding.UTF8.GetBytes(client.authProvider.Credentials.Key.GetString())); + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < keyBytes.Length; i++) + { + builder.Append(keyBytes[i].ToString("x2")); + } + + var key = builder.ToString(); int waitTime; RateLimitObject rlo; @@ -69,5 +80,13 @@ namespace CryptoExchange.Net.RateLimiter return new CallResult(waitTime, null); } + + /// + /// Dispose + /// + public void Dispose() + { + encryptor.Dispose(); + } } } From 7a54625bb59504eb0037417ec431706959e2cca5 Mon Sep 17 00:00:00 2001 From: Jkorf Date: Thu, 10 Dec 2020 15:21:10 +0100 Subject: [PATCH 22/22] Nullability, updated version --- .../Authentication/ApiCredentials.cs | 2 +- CryptoExchange.Net/BaseClient.cs | 7 ++++--- .../Converters/ArrayConverter.cs | 7 +++++-- CryptoExchange.Net/Converters/BaseConverter.cs | 6 +++--- .../Converters/TimestampConverter.cs | 9 ++++++--- .../TimestampNanoSecondsConverter.cs | 6 +++--- .../Converters/TimestampSecondsConverter.cs | 9 ++++++--- .../Converters/UTCDateTimeConverter.cs | 6 +++--- CryptoExchange.Net/CryptoExchange.Net.csproj | 8 ++++---- CryptoExchange.Net/CryptoExchange.Net.xml | 18 +++++++++++++++--- CryptoExchange.Net/Objects/CallResult.cs | 14 +++++++++++--- README.md | 5 +++++ 12 files changed, 66 insertions(+), 31 deletions(-) diff --git a/CryptoExchange.Net/Authentication/ApiCredentials.cs b/CryptoExchange.Net/Authentication/ApiCredentials.cs index 8900db9..e567e9f 100644 --- a/CryptoExchange.Net/Authentication/ApiCredentials.cs +++ b/CryptoExchange.Net/Authentication/ApiCredentials.cs @@ -109,7 +109,7 @@ namespace CryptoExchange.Net.Authentication { if (data[key] == null) return null; - return (string) data[key]; + return (string) data[key]!; } /// diff --git a/CryptoExchange.Net/BaseClient.cs b/CryptoExchange.Net/BaseClient.cs index a6749f1..60d6715 100644 --- a/CryptoExchange.Net/BaseClient.cs +++ b/CryptoExchange.Net/BaseClient.cs @@ -297,7 +297,8 @@ namespace CryptoExchange.Net if (ignore != null) continue; - properties.Add(attr == null ? prop.Name : ((JsonPropertyAttribute)attr).PropertyName); + var propertyName = ((JsonPropertyAttribute?) attr)?.PropertyName; + properties.Add(propertyName ?? prop.Name); } foreach (var token in obj) { @@ -319,12 +320,12 @@ namespace CryptoExchange.Net properties.Remove(d); var propType = GetProperty(d, props)?.PropertyType; - if (propType == null) + if (propType == null || token.Value == null) continue; if (!IsSimple(propType) && propType != typeof(DateTime)) { if (propType.IsArray && token.Value.HasValues && ((JArray)token.Value).Any() && ((JArray)token.Value)[0] is JObject) - CheckObject(propType.GetElementType(), (JObject)token.Value[0], requestId); + CheckObject(propType.GetElementType()!, (JObject)token.Value[0]!, requestId); else if (token.Value is JObject o) CheckObject(propType, o, requestId); } diff --git a/CryptoExchange.Net/Converters/ArrayConverter.cs b/CryptoExchange.Net/Converters/ArrayConverter.cs index 4d7b8bc..c06181c 100644 --- a/CryptoExchange.Net/Converters/ArrayConverter.cs +++ b/CryptoExchange.Net/Converters/ArrayConverter.cs @@ -21,7 +21,7 @@ namespace CryptoExchange.Net.Converters } /// - public override object? ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { if (objectType == typeof(JToken)) return JToken.Load(reader); @@ -115,8 +115,11 @@ namespace CryptoExchange.Net.Converters } /// - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) { + if (value == null) + return; + writer.WriteStartArray(); var props = value.GetType().GetProperties(); var ordered = props.OrderBy(p => p.GetCustomAttribute()?.Index); diff --git a/CryptoExchange.Net/Converters/BaseConverter.cs b/CryptoExchange.Net/Converters/BaseConverter.cs index b21a521..14767b7 100644 --- a/CryptoExchange.Net/Converters/BaseConverter.cs +++ b/CryptoExchange.Net/Converters/BaseConverter.cs @@ -28,9 +28,9 @@ namespace CryptoExchange.Net.Converters } /// - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) { - var stringValue = GetValue((T) value); + var stringValue = value == null? null: GetValue((T) value); if (quotes) writer.WriteValue(stringValue); else @@ -38,7 +38,7 @@ namespace CryptoExchange.Net.Converters } /// - public override object? ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { if (reader.Value == null) return null; diff --git a/CryptoExchange.Net/Converters/TimestampConverter.cs b/CryptoExchange.Net/Converters/TimestampConverter.cs index f1b9103..977b7c1 100644 --- a/CryptoExchange.Net/Converters/TimestampConverter.cs +++ b/CryptoExchange.Net/Converters/TimestampConverter.cs @@ -15,7 +15,7 @@ namespace CryptoExchange.Net.Converters } /// - public override object? ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { if (reader.Value == null) return null; @@ -25,9 +25,12 @@ namespace CryptoExchange.Net.Converters } /// - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) { - writer.WriteValue((long)Math.Round(((DateTime)value - new DateTime(1970, 1, 1)).TotalMilliseconds)); + if(value == null) + writer.WriteValue((DateTime?)null); + else + writer.WriteValue((long)Math.Round(((DateTime)value - new DateTime(1970, 1, 1)).TotalMilliseconds)); } } } diff --git a/CryptoExchange.Net/Converters/TimestampNanoSecondsConverter.cs b/CryptoExchange.Net/Converters/TimestampNanoSecondsConverter.cs index 80727b6..90b023c 100644 --- a/CryptoExchange.Net/Converters/TimestampNanoSecondsConverter.cs +++ b/CryptoExchange.Net/Converters/TimestampNanoSecondsConverter.cs @@ -17,7 +17,7 @@ namespace CryptoExchange.Net.Converters } /// - public override object? ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { if (reader.Value == null) return null; @@ -27,9 +27,9 @@ namespace CryptoExchange.Net.Converters } /// - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) { - writer.WriteValue((long)Math.Round(((DateTime)value - new DateTime(1970, 1, 1)).Ticks / ticksPerNanosecond)); + writer.WriteValue((long)Math.Round(((DateTime)value! - new DateTime(1970, 1, 1)).Ticks / ticksPerNanosecond)); } } } diff --git a/CryptoExchange.Net/Converters/TimestampSecondsConverter.cs b/CryptoExchange.Net/Converters/TimestampSecondsConverter.cs index 1b2264a..63a83eb 100644 --- a/CryptoExchange.Net/Converters/TimestampSecondsConverter.cs +++ b/CryptoExchange.Net/Converters/TimestampSecondsConverter.cs @@ -16,7 +16,7 @@ namespace CryptoExchange.Net.Converters } /// - public override object? ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { if (reader.Value == null) return null; @@ -29,9 +29,12 @@ namespace CryptoExchange.Net.Converters } /// - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) { - writer.WriteValue((long)Math.Round(((DateTime)value - new DateTime(1970, 1, 1)).TotalSeconds)); + if (value == null) + writer.WriteValue((DateTime?)null); + else + writer.WriteValue((long)Math.Round(((DateTime)value! - new DateTime(1970, 1, 1)).TotalSeconds)); } } } diff --git a/CryptoExchange.Net/Converters/UTCDateTimeConverter.cs b/CryptoExchange.Net/Converters/UTCDateTimeConverter.cs index 9690f7f..efd84f8 100644 --- a/CryptoExchange.Net/Converters/UTCDateTimeConverter.cs +++ b/CryptoExchange.Net/Converters/UTCDateTimeConverter.cs @@ -9,20 +9,20 @@ namespace CryptoExchange.Net.Converters public class UTCDateTimeConverter: JsonConverter { /// - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) { writer.WriteValue(JsonConvert.SerializeObject(value)); } /// - public override object? ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { if (reader.Value == null) return null; DateTime value; if (reader.Value is string s) - value = (DateTime)JsonConvert.DeserializeObject(s); + value = (DateTime)JsonConvert.DeserializeObject(s)!; else value = (DateTime) reader.Value; diff --git a/CryptoExchange.Net/CryptoExchange.Net.csproj b/CryptoExchange.Net/CryptoExchange.Net.csproj index ecfb92c..b006a20 100644 --- a/CryptoExchange.Net/CryptoExchange.Net.csproj +++ b/CryptoExchange.Net/CryptoExchange.Net.csproj @@ -1,4 +1,4 @@ - + netstandard2.0;netstandard2.1 @@ -6,13 +6,13 @@ CryptoExchange.Net JKorf A base package for implementing cryptocurrency exchange API's - 3.2.1 - 3.2.0 + 3.3.0 + 3.3.0 false https://github.com/JKorf/CryptoExchange.Net en true - 3.2.1 - Fixed error code parsing + 3.3.0 - Added client name, Added common interfaces, Fixed api key plain text storing in RateLimitterApiKey enable 8.0 MIT diff --git a/CryptoExchange.Net/CryptoExchange.Net.xml b/CryptoExchange.Net/CryptoExchange.Net.xml index 148cefe..4e8ba34 100644 --- a/CryptoExchange.Net/CryptoExchange.Net.xml +++ b/CryptoExchange.Net/CryptoExchange.Net.xml @@ -1636,9 +1636,7 @@ Create an error result - - - + @@ -1666,6 +1664,20 @@ + + + Create new based on existing + + + + + + Create from a call result + + + + + Create an error result diff --git a/CryptoExchange.Net/Objects/CallResult.cs b/CryptoExchange.Net/Objects/CallResult.cs index 23409e5..d19e8f9 100644 --- a/CryptoExchange.Net/Objects/CallResult.cs +++ b/CryptoExchange.Net/Objects/CallResult.cs @@ -158,9 +158,7 @@ namespace CryptoExchange.Net.Objects /// /// Create an error result /// - /// - /// - /// + /// /// public static WebCallResult CreateErrorResult(WebCallResult result) { @@ -199,12 +197,22 @@ namespace CryptoExchange.Net.Objects ResponseHeaders = responseHeaders; } + /// + /// Create new based on existing + /// + /// public WebCallResult(WebCallResult callResult): base(callResult.Data, callResult.Error) { ResponseHeaders = callResult.ResponseHeaders; ResponseStatusCode = callResult.ResponseStatusCode; } + /// + /// Create from a call result + /// + /// + /// + /// public static WebCallResult CreateFrom(WebCallResult source) where Y : T { return new WebCallResult(source.ResponseStatusCode, source.ResponseHeaders, (T)source.Data, source.Error); diff --git a/README.md b/README.md index 30d957b..fecb8fe 100644 --- a/README.md +++ b/README.md @@ -203,6 +203,11 @@ The order book will automatically reconnect when the connection is lost and resy To stop synchronizing an order book use the `Stop` method. ## Release notes +* Version 3.3.0 - 10 dec 2020 + * Added client name + * Added common interfaces + * Fixed api key plain text storing in RateLimitterApiKey + * Version 3.2.1 - 19 nov 2020 * Fixed error code parsing