diff --git a/CryptoExchange.Net.UnitTests/SocketClientTests.cs b/CryptoExchange.Net.UnitTests/SocketClientTests.cs
index 2b9ec6a..bacb863 100644
--- a/CryptoExchange.Net.UnitTests/SocketClientTests.cs
+++ b/CryptoExchange.Net.UnitTests/SocketClientTests.cs
@@ -26,7 +26,7 @@ namespace CryptoExchange.Net.UnitTests
//assert
Assert.IsTrue(client.BaseAddress == "http://test.address.com/");
- Assert.IsTrue(client.ReconnectInterval.TotalSeconds == 6);
+ Assert.IsTrue(client.ClientOptions.ReconnectInterval.TotalSeconds == 6);
}
[TestCase(true)]
diff --git a/CryptoExchange.Net/BaseClient.cs b/CryptoExchange.Net/BaseClient.cs
index 7cd8d3a..aa4a652 100644
--- a/CryptoExchange.Net/BaseClient.cs
+++ b/CryptoExchange.Net/BaseClient.cs
@@ -21,35 +21,19 @@ namespace CryptoExchange.Net
///
public abstract class BaseClient : IDisposable
{
- ///
- /// The address of the client
- ///
- public string BaseAddress { get; }
///
/// The name of the exchange the client is for
///
- public string ExchangeName { get; }
+ internal string ExchangeName { get; }
///
/// The log object
///
protected internal Log log;
///
- /// The api proxy
- ///
- protected ApiProxy? apiProxy;
- ///
/// The authentication provider
///
protected internal AuthenticationProvider? authProvider;
///
- /// Should check objects for missing properties based on the model and the received JSON
- ///
- public bool ShouldCheckObjects { get; set; }
- ///
- /// If true, the CallResult and DataEvent objects should also contain the originally received json data in the OriginalDaa property
- ///
- public bool OutputOriginalData { get; private set; }
- ///
/// The last used id, use NextId() to get the next id and up this
///
protected static int lastId;
@@ -68,9 +52,9 @@ namespace CryptoExchange.Net
});
///
- /// Last id used
+ /// Provided client options
///
- public static int LastId => lastId;
+ public ClientOptions ClientOptions { get; }
///
/// ctor
@@ -85,13 +69,12 @@ namespace CryptoExchange.Net
log.UpdateWriters(options.LogWriters);
log.Level = options.LogLevel;
+ ClientOptions = options;
+
ExchangeName = exchangeName;
- OutputOriginalData = options.OutputOriginalData;
- BaseAddress = options.BaseAddress;
- apiProxy = options.Proxy;
+ //BaseAddress = options.BaseAddress;
log.Write(LogLevel.Debug, $"Client configuration: {options}, CryptoExchange.Net: v{typeof(BaseClient).Assembly.GetName().Version}, {ExchangeName}.Net: v{GetType().Assembly.GetName().Version}");
- ShouldCheckObjects = options.ShouldCheckObjects;
}
///
@@ -145,11 +128,10 @@ namespace CryptoExchange.Net
///
/// The type to deserialize into
/// The data to deserialize
- /// Whether or not the parsing should be checked for missing properties (will output data to the logging if log verbosity is Debug)
/// A specific serializer to use
/// Id of the request the data is returned from (used for grouping logging by request)
///
- protected CallResult Deserialize(string data, bool? checkObject = null, JsonSerializer? serializer = null, int? requestId = null)
+ protected CallResult Deserialize(string data, JsonSerializer? serializer = null, int? requestId = null)
{
var tokenResult = ValidateJson(data);
if (!tokenResult)
@@ -158,7 +140,7 @@ namespace CryptoExchange.Net
return new CallResult(default, tokenResult.Error);
}
- return Deserialize(tokenResult.Data, checkObject, serializer, requestId);
+ return Deserialize(tokenResult.Data, serializer, requestId);
}
///
@@ -166,39 +148,16 @@ namespace CryptoExchange.Net
///
/// The type to deserialize into
/// The data to deserialize
- /// Whether or not the parsing should be checked for missing properties (will output data to the logging if log verbosity is Debug)
/// A specific serializer to use
/// Id of the request the data is returned from (used for grouping logging by request)
///
- protected CallResult Deserialize(JToken obj, bool? checkObject = null, JsonSerializer? serializer = null, int? requestId = null)
+ protected CallResult Deserialize(JToken obj, JsonSerializer? serializer = null, int? requestId = null)
{
if (serializer == null)
serializer = defaultSerializer;
try
{
- if ((checkObject ?? ShouldCheckObjects)&& log.Level <= LogLevel.Debug)
- {
- // This checks the input JToken object against the class it is being serialized into and outputs any missing fields
- // in either the input or the class
- try
- {
- if (obj is JObject o)
- {
- CheckObject(typeof(T), o, requestId);
- }
- else if (obj is JArray j)
- {
- if (j.HasValues && j[0] is JObject jObject)
- CheckObject(typeof(T).GetElementType(), jObject, requestId);
- }
- }
- catch (Exception e)
- {
- log.Write(LogLevel.Debug, $"{(requestId != null ? $"[{ requestId}] " : "")}Failed to check response data: " + (e.InnerException?.Message ?? e.Message));
- }
- }
-
return new CallResult(obj.ToObject(serializer), null);
}
catch (JsonReaderException jre)
@@ -243,12 +202,12 @@ namespace CryptoExchange.Net
// If we have to output the original json data or output the data into the logging we'll have to read to full response
// in order to log/return the json data
- if (OutputOriginalData || log.Level <= LogLevel.Debug)
+ if (ClientOptions.OutputOriginalData || log.Level <= LogLevel.Debug)
{
var data = await reader.ReadToEndAsync().ConfigureAwait(false);
log.Write(LogLevel.Debug, $"{(requestId != null ? $"[{requestId}] ": "")}Response received{(elapsedMilliseconds != null ? $" in {elapsedMilliseconds}" : " ")}ms: {data}");
- var result = Deserialize(data, null, serializer, requestId);
- if(OutputOriginalData)
+ var result = Deserialize(data, serializer, requestId);
+ if(ClientOptions.OutputOriginalData)
result.OriginalData = data;
return result;
}
@@ -308,116 +267,6 @@ namespace CryptoExchange.Net
return await reader.ReadToEndAsync().ConfigureAwait(false);
}
- private void CheckObject(Type type, JObject obj, int? requestId = null)
- {
- if (type == null)
- return;
-
- if (type.GetCustomAttribute(true) != null)
- // If type has a custom JsonConverter we assume this will handle property mapping
- return;
-
- if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Dictionary<,>))
- return;
-
- if (!obj.HasValues && type != typeof(object))
- {
- log.Write(LogLevel.Warning, $"{(requestId != null ? $"[{requestId}] " : "")}Expected `{type.Name}`, but received object was empty");
- return;
- }
-
- var isDif = false;
- var properties = new List();
- var props = type.GetProperties(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.FlattenHierarchy);
- foreach (var prop in props)
- {
- var attr = prop.GetCustomAttributes(typeof(JsonPropertyAttribute), false).FirstOrDefault();
- var ignore = prop.GetCustomAttributes(typeof(JsonIgnoreAttribute), false).FirstOrDefault();
- if (ignore != null)
- continue;
-
- var propertyName = ((JsonPropertyAttribute?) attr)?.PropertyName;
- properties.Add(propertyName ?? prop.Name);
- }
- foreach (var token in obj)
- {
- var d = properties.FirstOrDefault(p => p == token.Key);
- if (d == null)
- {
- d = properties.SingleOrDefault(p => string.Equals(p, token.Key, StringComparison.CurrentCultureIgnoreCase));
- if (d == null)
- {
- if (!(type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Dictionary<,>)))
- {
- log.Write(LogLevel.Warning, $"{(requestId != null ? $"[{requestId}] " : "")}Local object doesn't have property `{token.Key}` expected in type `{type.Name}`");
- isDif = true;
- }
- continue;
- }
- }
-
- properties.Remove(d);
-
- var propType = GetProperty(d, props)?.PropertyType;
- 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);
- else if (token.Value is JObject o)
- CheckObject(propType, o, requestId);
- }
- }
-
- foreach (var prop in properties)
- {
- var propInfo = props.First(p => p.Name == prop ||
- ((JsonPropertyAttribute)p.GetCustomAttributes(typeof(JsonPropertyAttribute), false).FirstOrDefault())?.PropertyName == prop);
- var optional = propInfo.GetCustomAttributes(typeof(JsonOptionalPropertyAttribute), false).FirstOrDefault();
- if (optional != null)
- continue;
-
- isDif = true;
- log.Write(LogLevel.Warning, $"{(requestId != null ? $"[{requestId}] " : "")}Local object has property `{prop}` but was not found in received object of type `{type.Name}`");
- }
-
- if (isDif)
- log.Write(LogLevel.Debug, $"{(requestId != null ? $"[{ requestId}] " : "")}Returned data: " + obj);
- }
-
- private static PropertyInfo? GetProperty(string name, IEnumerable props)
- {
- foreach (var prop in props)
- {
- var attr = prop.GetCustomAttributes(typeof(JsonPropertyAttribute), false).FirstOrDefault();
- if (attr == null)
- {
- if (string.Equals(prop.Name, name, StringComparison.CurrentCultureIgnoreCase))
- return prop;
- }
- else
- {
- if (((JsonPropertyAttribute)attr).PropertyName == name)
- return prop;
- }
- }
- return null;
- }
-
- private static bool IsSimple(Type type)
- {
- if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
- {
- // nullable type, check if the nested type is simple.
- return IsSimple(type.GetGenericArguments()[0]);
- }
- return type.IsPrimitive
- || type.IsEnum
- || type == typeof(string)
- || type == typeof(decimal);
- }
-
///
/// Generate a new unique id. The id is staticly stored so it is guarenteed to be unique across different client instances
///
diff --git a/CryptoExchange.Net/CryptoExchange.Net.xml b/CryptoExchange.Net/CryptoExchange.Net.xml
index 2100834..e3846fd 100644
--- a/CryptoExchange.Net/CryptoExchange.Net.xml
+++ b/CryptoExchange.Net/CryptoExchange.Net.xml
@@ -204,11 +204,6 @@
The base for all clients, websocket client and rest client
-
-
- The address of the client
-
-
The name of the exchange the client is for
@@ -219,26 +214,11 @@
The log object
-
-
- The api proxy
-
-
The authentication provider
-
-
- Should check objects for missing properties based on the model and the received JSON
-
-
-
-
- If true, the CallResult and DataEvent objects should also contain the originally received json data in the OriginalDaa property
-
-
The last used id, use NextId() to get the next id and up this
@@ -254,9 +234,9 @@
A default serializer
-
+
- Last id used
+ Provided client options
@@ -280,24 +260,22 @@
The data to parse
-
+
Deserialize a string into an object
The type to deserialize into
The data to deserialize
- Whether or not the parsing should be checked for missing properties (will output data to the logging if log verbosity is Debug)
A specific serializer to use
Id of the request the data is returned from (used for grouping logging by request)
-
+
Deserialize a JToken into an object
The type to deserialize into
The data to deserialize
- Whether or not the parsing should be checked for missing properties (will output data to the logging if log verbosity is Debug)
A specific serializer to use
Id of the request the data is returned from (used for grouping logging by request)
@@ -1233,31 +1211,11 @@
The factory for creating requests. Used for unit testing
-
-
- What should happen when hitting a rate limit
-
-
-
-
- List of active rate limiters
-
-
The total amount of requests made
-
-
- The base address of the API
-
-
-
-
- Client name
-
-
Adds a rate limiter to the client. There are 2 choices, the and the .
@@ -1269,69 +1227,24 @@
Removes all rate limiters from this client
-
+
- Ping to see if the server is reachable
+ Client options
- The roundtrip time of the ping request
-
-
-
- Ping to see if the server is reachable
-
- The roundtrip time of the ping request
Base class for socket API implementations
-
+
- The factory for creating sockets. Used for unit testing
+ Client options
-
-
- The time in between reconnect attempts
-
-
-
-
- Whether the client should try to auto reconnect when losing connection
-
-
-
-
- The base address of the API
-
-
-
-
-
-
-
-
-
-
- The max amount of concurrent socket connections
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- The current kilobytes per second of data being received by all connection from this client, averaged over the last 3 seconds
+ Incoming kilobytes per second of data
@@ -2273,6 +2186,14 @@
If true, the CallResult and DataEvent objects will also include the originally received json data in the OriginalData property
+
+
+ Copy the values of the def to the input
+
+
+
+
+
@@ -2281,39 +2202,11 @@
Base for order book options
-
-
- The name of the order book implementation
-
-
Whether or not checksum validation is enabled. Default is true, disabling will ignore checksum messages.
-
-
- Whether each update should have a consecutive id number. Used to identify and reconnect when numbers are skipped.
-
-
-
-
- Whether or not a level should be removed from the book when it's pushed out of scope of the limit. For example with a book of limit 10,
- when a new bid level is added which makes the total amount of bids 11, should the last bid entry be removed
-
-
-
-
- ctor
-
- The name of the order book implementation
- Whether each update should have a consecutive id number. Used to identify and reconnect when numbers are skipped.
- Whether or not a level should be removed from the book when it's pushed out of scope of the limit. For example with a book of limit 10,
- when a new bid is added which makes the total amount of bids 11, should the last bid entry be removed
-
-
-
-
Base client options
@@ -2329,21 +2222,18 @@
The api credentials
-
-
- Should check objects for missing properties based on the model and the received JSON
-
-
Proxy to use
-
+
- ctor
+ Copy the values of the def to the input
- The base address to use
+
+
+
@@ -2373,25 +2263,13 @@
Http client to use. If a HttpClient is provided in this property the RequestTimeout and Proxy options will be ignored in requests and should be set on the provided HttpClient instance
-
+
- ctor
-
- The base address of the API
-
-
-
- ctor
-
- The base address of the API
- Shared http client instance
-
-
-
- Create a copy of the options
+ Copy the values of the def to the input
-
+
+
@@ -2443,18 +2321,13 @@
single connection will also increase the amount of traffic on that single connection, potentially leading to issues.
-
+
- ctor
-
- The base address to use
-
-
-
- Create a copy of the options
+ Copy the values of the def to the input
-
+
+
@@ -2514,6 +2387,16 @@
The log
+
+
+ Whether update numbers are consecutive
+
+
+
+
+ Whether levels should be strictly enforced
+
+
If order book is set
@@ -2599,10 +2482,11 @@
BestBid/BesAsk returned as a pair
-
+
ctor
+
@@ -2936,16 +2820,6 @@
What request body should be set when no data is send (only used in combination with postParametersPosition.InBody)
-
-
- Timeout for requests. This setting is ignored when injecting a HttpClient in the options, requests timeouts should be set on the client then.
-
-
-
-
- What should happen when running into a rate limit
-
-
List of rate limiters
@@ -2961,6 +2835,11 @@
Request headers to be sent with each request
+
+
+ Client options
+
+
ctor
@@ -2980,18 +2859,6 @@
Removes all rate limiters from this client
-
-
- Ping to see if the server is reachable
-
- The roundtrip time of the ping request
-
-
-
- Ping to see if the server is reachable
-
- The roundtrip time of the ping request
-
Execute a request to the uri and deserialize the response into the provided type parameter
@@ -3077,35 +2944,11 @@
Semaphore used while creating sockets
-
-
-
-
-
-
-
-
-
-
-
-
The max amount of concurrent socket connections
-
-
-
-
-
-
-
-
-
-
-
-
Delegate used for processing byte data received from socket connections before it is processed by handlers
@@ -3157,6 +3000,11 @@
The current kilobytes per second of data being received by all connection from this client, averaged over the last 3 seconds
+
+
+ Client options
+
+
ctor
@@ -3312,7 +3160,7 @@
-
+
Add a subscription to a connection
@@ -3943,7 +3791,6 @@
-
@@ -3954,7 +3801,6 @@
-
@@ -4053,5 +3899,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/Interfaces/IRestClient.cs b/CryptoExchange.Net/Interfaces/IRestClient.cs
index 65c8c30..3778958 100644
--- a/CryptoExchange.Net/Interfaces/IRestClient.cs
+++ b/CryptoExchange.Net/Interfaces/IRestClient.cs
@@ -17,31 +17,11 @@ namespace CryptoExchange.Net.Interfaces
///
IRequestFactory RequestFactory { get; set; }
- ///
- /// What should happen when hitting a rate limit
- ///
- RateLimitingBehaviour RateLimitBehaviour { get; }
-
- ///
- /// List of active rate limiters
- ///
- IEnumerable RateLimiters { get; }
-
///
/// The total amount of requests made
///
int TotalRequestsMade { get; }
- ///
- /// The base address of the API
- ///
- string BaseAddress { get; }
-
- ///
- /// Client name
- ///
- string ExchangeName { get; }
-
///
/// Adds a rate limiter to the client. There are 2 choices, the and the .
///
@@ -54,15 +34,8 @@ namespace CryptoExchange.Net.Interfaces
void RemoveRateLimiters();
///
- /// Ping to see if the server is reachable
+ /// Client options
///
- /// The roundtrip time of the ping request
- CallResult Ping(CancellationToken ct = default);
-
- ///
- /// Ping to see if the server is reachable
- ///
- /// The roundtrip time of the ping request
- Task> PingAsync(CancellationToken ct = default);
+ RestClientOptions ClientOptions { get; }
}
}
\ No newline at end of file
diff --git a/CryptoExchange.Net/Interfaces/ISocketClient.cs b/CryptoExchange.Net/Interfaces/ISocketClient.cs
index 3b0b5c8..12964de 100644
--- a/CryptoExchange.Net/Interfaces/ISocketClient.cs
+++ b/CryptoExchange.Net/Interfaces/ISocketClient.cs
@@ -11,48 +11,14 @@ namespace CryptoExchange.Net.Interfaces
public interface ISocketClient: IDisposable
{
///
- /// The factory for creating sockets. Used for unit testing
+ /// Client options
///
- IWebsocketFactory SocketFactory { get; set; }
+ SocketClientOptions ClientOptions { get; }
///
- /// The time in between reconnect attempts
+ /// Incoming kilobytes per second of data
///
- TimeSpan ReconnectInterval { get; }
-
- ///
- /// Whether the client should try to auto reconnect when losing connection
- ///
- bool AutoReconnect { get; }
-
- ///
- /// The base address of the API
- ///
- string BaseAddress { get; }
-
- ///
- TimeSpan ResponseTimeout { get; }
-
- ///
- TimeSpan SocketNoDataTimeout { get; }
-
- ///
- /// The max amount of concurrent socket connections
- ///
- int MaxSocketConnections { get; }
-
- ///
- int SocketCombineTarget { get; }
- ///
- int? MaxReconnectTries { get; }
- ///
- int? MaxResubscribeTries { get; }
- ///
- int MaxConcurrentResubscriptionsPerSocket { get; }
- ///
- /// The current kilobytes per second of data being received by all connection from this client, averaged over the last 3 seconds
- ///
- double IncomingKbps { get; }
+ public double IncomingKbps { get; }
///
/// Unsubscribe from a stream
diff --git a/CryptoExchange.Net/Objects/Options.cs b/CryptoExchange.Net/Objects/Options.cs
index e452a05..45c22f4 100644
--- a/CryptoExchange.Net/Objects/Options.cs
+++ b/CryptoExchange.Net/Objects/Options.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Linq;
using System.Net.Http;
using CryptoExchange.Net.Authentication;
using CryptoExchange.Net.Interfaces;
@@ -16,7 +17,7 @@ namespace CryptoExchange.Net.Objects
///
/// The minimum log level to output. Setting it to null will send all messages to the registered ILoggers.
///
- public LogLevel? LogLevel { get; set; } = Microsoft.Extensions.Logging.LogLevel.Information;
+ public LogLevel LogLevel { get; set; } = LogLevel.Information;
///
/// The log writers
@@ -28,6 +29,19 @@ namespace CryptoExchange.Net.Objects
///
public bool OutputOriginalData { get; set; } = false;
+ ///
+ /// Copy the values of the def to the input
+ ///
+ ///
+ ///
+ ///
+ public void Copy(T input, T def) where T : BaseOptions
+ {
+ input.LogLevel = def.LogLevel;
+ input.LogWriters = def.LogWriters.ToList();
+ input.OutputOriginalData = def.OutputOriginalData;
+ }
+
///
public override string ToString()
{
@@ -39,47 +53,11 @@ namespace CryptoExchange.Net.Objects
/// Base for order book options
///
public class OrderBookOptions : BaseOptions
- {
- ///
- /// The name of the order book implementation
- ///
- public string OrderBookName { get; }
-
+ {
///
/// Whether or not checksum validation is enabled. Default is true, disabling will ignore checksum messages.
///
public bool ChecksumValidationEnabled { get; set; } = true;
-
- ///
- /// Whether each update should have a consecutive id number. Used to identify and reconnect when numbers are skipped.
- ///
- public bool SequenceNumbersAreConsecutive { get; }
-
- ///
- /// Whether or not a level should be removed from the book when it's pushed out of scope of the limit. For example with a book of limit 10,
- /// when a new bid level is added which makes the total amount of bids 11, should the last bid entry be removed
- ///
- public bool StrictLevels { get; }
-
- ///
- /// ctor
- ///
- /// The name of the order book implementation
- /// Whether each update should have a consecutive id number. Used to identify and reconnect when numbers are skipped.
- /// Whether or not a level should be removed from the book when it's pushed out of scope of the limit. For example with a book of limit 10,
- /// when a new bid is added which makes the total amount of bids 11, should the last bid entry be removed
- public OrderBookOptions(string name, bool sequencesAreConsecutive, bool strictLevels)
- {
- OrderBookName = name;
- SequenceNumbersAreConsecutive = sequencesAreConsecutive;
- StrictLevels = strictLevels;
- }
-
- ///
- public override string ToString()
- {
- return $"{base.ToString()}, OrderBookName: {OrderBookName}, SequenceNumbersAreConsequtive: {SequenceNumbersAreConsecutive}, StrictLevels: {StrictLevels}";
- }
}
///
@@ -87,7 +65,7 @@ namespace CryptoExchange.Net.Objects
///
public class ClientOptions : BaseOptions
{
- private string _baseAddress;
+ private string _baseAddress = string.Empty;
///
/// The base address of the client
@@ -97,6 +75,9 @@ namespace CryptoExchange.Net.Objects
get => _baseAddress;
set
{
+ if (value == null)
+ return;
+
var newValue = value;
if (!newValue.EndsWith("/"))
newValue += "/";
@@ -109,25 +90,24 @@ namespace CryptoExchange.Net.Objects
///
public ApiCredentials? ApiCredentials { get; set; }
- ///
- /// Should check objects for missing properties based on the model and the received JSON
- ///
- public bool ShouldCheckObjects { get; set; } = false;
-
///
/// Proxy to use
///
public ApiProxy? Proxy { get; set; }
///
- /// ctor
+ /// Copy the values of the def to the input
///
- /// The base address to use
-#pragma warning disable 8618
- public ClientOptions(string baseAddress)
-#pragma warning restore 8618
+ ///
+ ///
+ ///
+ public new void Copy(T input, T def) where T : ClientOptions
{
- BaseAddress = baseAddress;
+ base.Copy(input, def);
+
+ input.BaseAddress = def.BaseAddress;
+ input.ApiCredentials = def.ApiCredentials?.Copy();
+ input.Proxy = def.Proxy;
}
///
@@ -163,44 +143,19 @@ namespace CryptoExchange.Net.Objects
public HttpClient? HttpClient { get; set; }
///
- /// ctor
- ///
- /// The base address of the API
- public RestClientOptions(string baseAddress): base(baseAddress)
- {
- }
- ///
- /// ctor
- ///
- /// The base address of the API
- /// Shared http client instance
- public RestClientOptions(HttpClient httpClient, string baseAddress) : base(baseAddress)
- {
- HttpClient = httpClient;
- }
- ///
- /// Create a copy of the options
+ /// Copy the values of the def to the input
///
///
- ///
- public T Copy() where T : RestClientOptions, new()
+ ///
+ ///
+ public new void Copy(T input, T def) where T : RestClientOptions
{
- var copy = new T
- {
- BaseAddress = BaseAddress,
- LogLevel = LogLevel,
- Proxy = Proxy,
- LogWriters = LogWriters,
- RateLimiters = RateLimiters,
- RateLimitingBehaviour = RateLimitingBehaviour,
- RequestTimeout = RequestTimeout,
- HttpClient = HttpClient
- };
-
- if (ApiCredentials != null)
- copy.ApiCredentials = ApiCredentials.Copy();
-
- return copy;
+ base.Copy(input, def);
+
+ input.HttpClient = def.HttpClient;
+ input.RateLimiters = def.RateLimiters.ToList();
+ input.RateLimitingBehaviour = def.RateLimitingBehaviour;
+ input.RequestTimeout = def.RequestTimeout;
}
///
@@ -257,36 +212,23 @@ namespace CryptoExchange.Net.Objects
public int? SocketSubscriptionsCombineTarget { get; set; }
///
- /// ctor
- ///
- /// The base address to use
- public SocketClientOptions(string baseAddress) : base(baseAddress)
- {
- }
-
- ///
- /// Create a copy of the options
+ /// Copy the values of the def to the input
///
///
- ///
- public T Copy() where T : SocketClientOptions, new()
+ ///
+ ///
+ public new void Copy(T input, T def) where T : SocketClientOptions
{
- var copy = new T
- {
- BaseAddress = BaseAddress,
- LogLevel = LogLevel,
- Proxy = Proxy,
- LogWriters = LogWriters,
- AutoReconnect = AutoReconnect,
- ReconnectInterval = ReconnectInterval,
- SocketResponseTimeout = SocketResponseTimeout,
- SocketSubscriptionsCombineTarget = SocketSubscriptionsCombineTarget
- };
+ base.Copy(input, def);
- if (ApiCredentials != null)
- copy.ApiCredentials = ApiCredentials.Copy();
-
- return copy;
+ input.AutoReconnect = def.AutoReconnect;
+ input.ReconnectInterval = def.ReconnectInterval;
+ input.MaxReconnectTries = def.MaxReconnectTries;
+ input.MaxResubscribeTries = def.MaxResubscribeTries;
+ input.MaxConcurrentResubscriptionsPerSocket = def.MaxConcurrentResubscriptionsPerSocket;
+ input.SocketResponseTimeout = def.SocketResponseTimeout;
+ input.SocketNoDataTimeout = def.SocketNoDataTimeout;
+ input.SocketSubscriptionsCombineTarget = def.SocketSubscriptionsCombineTarget;
}
///
diff --git a/CryptoExchange.Net/OrderBook/SymbolOrderBook.cs b/CryptoExchange.Net/OrderBook/SymbolOrderBook.cs
index 2a8c937..17d9136 100644
--- a/CryptoExchange.Net/OrderBook/SymbolOrderBook.cs
+++ b/CryptoExchange.Net/OrderBook/SymbolOrderBook.cs
@@ -35,8 +35,7 @@ namespace CryptoExchange.Net.OrderBook
private OrderBookStatus status;
private UpdateSubscription? subscription;
- private readonly bool sequencesAreConsecutive;
- private readonly bool strictLevels;
+
private readonly bool validateChecksum;
private bool _stopProcessing;
@@ -53,6 +52,16 @@ namespace CryptoExchange.Net.OrderBook
///
protected Log log;
+ ///
+ /// Whether update numbers are consecutive
+ ///
+ protected bool sequencesAreConsecutive;
+
+ ///
+ /// Whether levels should be strictly enforced
+ ///
+ protected bool strictLevels;
+
///
/// If order book is set
///
@@ -199,9 +208,10 @@ namespace CryptoExchange.Net.OrderBook
///
/// ctor
///
+ ///
///
///
- protected SymbolOrderBook(string symbol, OrderBookOptions options)
+ protected SymbolOrderBook(string id, string symbol, OrderBookOptions options)
{
if (symbol == null)
throw new ArgumentNullException(nameof(symbol));
@@ -209,13 +219,11 @@ namespace CryptoExchange.Net.OrderBook
if (options == null)
throw new ArgumentNullException(nameof(options));
- Id = options.OrderBookName;
+ Id = id;
processBuffer = new List();
_processQueue = new ConcurrentQueue