mirror of
https://github.com/JKorf/CryptoExchange.Net.git
synced 2026-08-12 17:03:10 +00:00
d079796020
Performance update: Authentication Added Ed25519 signing support for NET8.0 and newer Added static methods on ApiCredentials to create credentials of a specific type Added static ApiCredentials.ReadFromFile method to read a key from file Added required abstract SupportedCredentialTypes property on AuthenticationProvider base class General Performance Added checks before logging statements to prevent overhead of building the log string if logging is not needed Added ExchangeHelpers.ProcessQueuedAsync method to process updates async Replaced locking object types from object to Lock in NET9.0 and newer Replaced some Task response types with ValueTask to prevent allocation overhead on hot paths Updated Json ArrayConverter to reduce some allocation overhead Updated Json BoolConverter to prevent boxing Updated Json DateTimeConverter to prevent boxing Updated Json EnumConverter caching to reduce lookup overhead Updated ExtensionMethods.CreateParamString to reduce allocations Updated ExtensionMethods.AppendPath to reduce overhead REST Refactored REST message processing to separate IRestMessageHandler instance Split RestApiClient.PrepareAsync into CheckTimeSync and RateLimitAsync Updated IRequest.Accept type from string to MediaTypeWithQualityHeaderValue to prevent creation on each request Updated IRequest.GetHeaders response type from KeyValuePair<string, string[]>[] to HttpRequestHeaders to prevent additional mapping Updated IResponse.ResponseHeaders type from KeyValuePair<string, string[]>[] to HttpResponseHeaders to prevent additional mapping Updated WebCallResult RequestHeaders and ResponseHeaders types to HttpRequestHeaders and HttpResponseHeaders Removed unnecessary empty dictionary initializations for each request Removed CallResult creation in internal methods to prevent having to create multiple versions for different result types Socket Added HighPerformance websocket client implementation which significantly reduces memory overhead and improves speed but with certain limitations Added MaxIndividualSubscriptionsPerConnection setting in SocketApiClient to limit the number of individual stream subscriptions on a connection Added SocketIndividualSubscriptionCombineTarget option to set the target number of individual stream subscriptions per connection Added new websocket message handling logic which is faster and reduces memory allocation Added UseUpdatedDeserialization option to toggle between updated deserialization and old deserialization Added Exchange property to DataEvent to prevent additional mapping overhead for Shared apis Refactored message callback to be sync instead of async to prevent async overhead Refactored CryptoExchangeWebSocketClient.IncomingKbps calculation to significantly reduce overhead Moved websocket client creation from SocketApiClient to SocketConnection Removed DataEvent.As and DataEvent.ToCallResult methods in favor of single ToType method Removed DataEvent creation on lower levels to prevent having to create multiple versions for different result types Removed Subscription<TSubResponse, TUnsubResponse> as its no longer used Other Added null check to ParameterCollection for required parameters Added Net10.0 target framework Updated dependency versions Updated Shared asset aliases check to be culture invariant Updated Error string representation Updated some namespaces Updated SymbolOrderBook processing of buffered updates to prevent additional allocation Removed ExchangeEvent type which is no longer needed Removed unused usings
347 lines
12 KiB
C#
347 lines
12 KiB
C#
using CryptoExchange.Net.Objects.Errors;
|
|
using System;
|
|
|
|
namespace CryptoExchange.Net.Objects
|
|
{
|
|
/// <summary>
|
|
/// Base class for errors
|
|
/// </summary>
|
|
public abstract class Error
|
|
{
|
|
|
|
private int? _code;
|
|
/// <summary>
|
|
/// The int error code the server returned; or the http status code int value if there was no error code.<br />
|
|
/// <br />
|
|
/// <i>Note:</i><br />
|
|
/// The <see cref="ErrorCode"/> property should be used for more generic error checking; it might contain a string error code if the server does not return an int code.
|
|
/// </summary>
|
|
public int? Code
|
|
{
|
|
get
|
|
{
|
|
if (_code.HasValue)
|
|
return _code;
|
|
|
|
return int.TryParse(ErrorCode, out var r) ? r : null;
|
|
}
|
|
set
|
|
{
|
|
_code = value;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// The error code returned by the server
|
|
/// </summary>
|
|
public string? ErrorCode { get; set; }
|
|
/// <summary>
|
|
/// The error description
|
|
/// </summary>
|
|
public string? ErrorDescription { get; set; }
|
|
|
|
/// <summary>
|
|
/// Error type
|
|
/// </summary>
|
|
public ErrorType ErrorType { get; set; }
|
|
|
|
/// <summary>
|
|
/// Whether the error is transient and can be retried
|
|
/// </summary>
|
|
public bool IsTransient { get; set; }
|
|
|
|
/// <summary>
|
|
/// The server message for the error that occurred
|
|
/// </summary>
|
|
public string? Message { get; set; }
|
|
|
|
/// <summary>
|
|
/// Underlying exception
|
|
/// </summary>
|
|
public Exception? Exception { get; set; }
|
|
|
|
/// <summary>
|
|
/// ctor
|
|
/// </summary>
|
|
protected Error(string? errorCode, ErrorInfo errorInfo, Exception? exception)
|
|
{
|
|
ErrorCode = errorCode;
|
|
ErrorType = errorInfo.ErrorType;
|
|
Message = errorInfo.Message;
|
|
ErrorDescription = errorInfo.ErrorDescription;
|
|
IsTransient = errorInfo.IsTransient;
|
|
Exception = exception;
|
|
}
|
|
|
|
/// <summary>
|
|
/// String representation
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public override string ToString()
|
|
{
|
|
return Code != null
|
|
? $"[{GetType().Name}.{ErrorType}] {Code}: {GetErrorDescription()}"
|
|
: $"[{GetType().Name}.{ErrorType}] {GetErrorDescription()}";
|
|
}
|
|
|
|
private string GetErrorDescription()
|
|
{
|
|
if (!string.IsNullOrEmpty(Message))
|
|
return Message!;
|
|
|
|
if (ErrorDescription != "Unknown error" || Exception == null)
|
|
return ErrorDescription!;
|
|
|
|
return Exception.Message;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Cant reach server error
|
|
/// </summary>
|
|
public class CantConnectError : Error
|
|
{
|
|
/// <summary>
|
|
/// Default error info
|
|
/// </summary>
|
|
protected static readonly ErrorInfo _errorInfo = new ErrorInfo(ErrorType.UnableToConnect, false, "Can't connect to the server");
|
|
|
|
/// <summary>
|
|
/// ctor
|
|
/// </summary>
|
|
public CantConnectError() : base(null, _errorInfo, null) { }
|
|
|
|
/// <summary>
|
|
/// ctor
|
|
/// </summary>
|
|
public CantConnectError(Exception? exception) : base(null, _errorInfo, exception) { }
|
|
|
|
/// <summary>
|
|
/// ctor
|
|
/// </summary>
|
|
protected CantConnectError(ErrorInfo info, Exception? exception) : base(null, info, exception) { }
|
|
}
|
|
|
|
/// <summary>
|
|
/// No api credentials provided while trying to access a private endpoint
|
|
/// </summary>
|
|
public class NoApiCredentialsError : Error
|
|
{
|
|
/// <summary>
|
|
/// Default error info
|
|
/// </summary>
|
|
protected static readonly ErrorInfo _errorInfo = new ErrorInfo(ErrorType.MissingCredentials, false, "No credentials provided for private endpoint");
|
|
|
|
/// <summary>
|
|
/// ctor
|
|
/// </summary>
|
|
public NoApiCredentialsError() : base(null, _errorInfo, null) { }
|
|
|
|
/// <summary>
|
|
/// ctor
|
|
/// </summary>
|
|
protected NoApiCredentialsError(ErrorInfo info, Exception? exception) : base(null, info, exception) { }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Error returned by the server
|
|
/// </summary>
|
|
public class ServerError : Error
|
|
{
|
|
/// <summary>
|
|
/// ctor
|
|
/// </summary>
|
|
public ServerError(ErrorInfo errorInfo, Exception? exception = null)
|
|
: base(null, errorInfo, exception) { }
|
|
|
|
/// <summary>
|
|
/// ctor
|
|
/// </summary>
|
|
public ServerError(int errorCode, ErrorInfo errorInfo, Exception? exception = null)
|
|
: this(errorCode.ToString(), errorInfo, exception) { }
|
|
|
|
/// <summary>
|
|
/// ctor
|
|
/// </summary>
|
|
public ServerError(string errorCode, ErrorInfo errorInfo, Exception? exception = null) : base(errorCode, errorInfo, exception) { }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Web error returned by the server
|
|
/// </summary>
|
|
public class WebError : Error
|
|
{
|
|
/// <summary>
|
|
/// Default error info
|
|
/// </summary>
|
|
protected static readonly ErrorInfo _errorInfo = new ErrorInfo(ErrorType.NetworkError, true, "Failed to complete the request to the server due to a network error");
|
|
|
|
/// <summary>
|
|
/// ctor
|
|
/// </summary>
|
|
public WebError(string? message = null, Exception? exception = null) : base(null, _errorInfo with { Message = (message?.Length > 0 ? _errorInfo.Message + ": " + message : _errorInfo.Message) }, exception) { }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Timeout error waiting for a response from the server
|
|
/// </summary>
|
|
public class TimeoutError : Error
|
|
{
|
|
/// <summary>
|
|
/// Default error info
|
|
/// </summary>
|
|
protected static readonly ErrorInfo _errorInfo = new ErrorInfo(ErrorType.Timeout, false, "Failed to receive a response from the server in time");
|
|
|
|
/// <summary>
|
|
/// ctor
|
|
/// </summary>
|
|
public TimeoutError(string? message = null, Exception? exception = null) : base(null, _errorInfo with { Message = (message?.Length > 0 ? _errorInfo.Message + ": " + message : _errorInfo.Message) }, exception) { }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Error while deserializing data
|
|
/// </summary>
|
|
public class DeserializeError : Error
|
|
{
|
|
/// <summary>
|
|
/// Default error info
|
|
/// </summary>
|
|
protected static readonly ErrorInfo _errorInfo = new ErrorInfo(ErrorType.DeserializationFailed, false, "Failed to deserialize data");
|
|
|
|
/// <summary>
|
|
/// ctor
|
|
/// </summary>
|
|
public DeserializeError(string? message = null, Exception? exception = null) : base(null, _errorInfo with { Message = (message?.Length > 0 ? _errorInfo.Message + ": " + message : _errorInfo.Message) }, exception) { }
|
|
}
|
|
|
|
/// <summary>
|
|
/// An invalid parameter has been provided
|
|
/// </summary>
|
|
public class ArgumentError : Error
|
|
{
|
|
/// <summary>
|
|
/// Default error info for missing parameter
|
|
/// </summary>
|
|
protected static readonly ErrorInfo _missingInfo = new ErrorInfo(ErrorType.MissingParameter, false, "Missing parameter");
|
|
/// <summary>
|
|
/// Default error info for invalid parameter
|
|
/// </summary>
|
|
protected static readonly ErrorInfo _invalidInfo = new ErrorInfo(ErrorType.InvalidParameter, false, "Invalid parameter");
|
|
|
|
/// <summary>
|
|
/// ctor
|
|
/// </summary>
|
|
public static ArgumentError Missing(string parameterName, string? message = null) => new ArgumentError(_missingInfo with { Message = message == null ? $"{_missingInfo.Message} '{parameterName}'" : $"{_missingInfo.Message} '{parameterName}': {message}" }, null);
|
|
|
|
/// <summary>
|
|
/// ctor
|
|
/// </summary>
|
|
public static ArgumentError Invalid(string parameterName, string message) => new ArgumentError(_invalidInfo with { Message = $"{_invalidInfo.Message} '{parameterName}': {message}" }, null);
|
|
|
|
/// <summary>
|
|
/// ctor
|
|
/// </summary>
|
|
protected ArgumentError(ErrorInfo info, Exception? exception) : base(null, info, exception) { }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Rate limit exceeded (client side)
|
|
/// </summary>
|
|
public abstract class BaseRateLimitError : Error
|
|
{
|
|
/// <summary>
|
|
/// When the request can be retried
|
|
/// </summary>
|
|
public DateTime? RetryAfter { get; set; }
|
|
|
|
/// <summary>
|
|
/// ctor
|
|
/// </summary>
|
|
protected BaseRateLimitError(ErrorInfo errorInfo, Exception? exception) : base(null, errorInfo, exception) { }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Rate limit exceeded (client side)
|
|
/// </summary>
|
|
public class ClientRateLimitError : BaseRateLimitError
|
|
{
|
|
/// <summary>
|
|
/// Default error info
|
|
/// </summary>
|
|
protected static readonly ErrorInfo _errorInfo = new ErrorInfo(ErrorType.RateLimitRequest, false, "Client rate limit exceeded");
|
|
|
|
/// <summary>
|
|
/// ctor
|
|
/// </summary>
|
|
public ClientRateLimitError(string? message = null, Exception? exception = null) : base(_errorInfo with { Message = (message?.Length > 0 ? _errorInfo.Message + ": " + message : _errorInfo.Message) }, exception) { }
|
|
|
|
/// <summary>
|
|
/// ctor
|
|
/// </summary>
|
|
protected ClientRateLimitError(ErrorInfo info, Exception? exception) : base(info, exception) { }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Rate limit exceeded (server side)
|
|
/// </summary>
|
|
public class ServerRateLimitError : BaseRateLimitError
|
|
{
|
|
/// <summary>
|
|
/// Default error info
|
|
/// </summary>
|
|
protected static readonly ErrorInfo _errorInfo = new ErrorInfo(ErrorType.RateLimitRequest, false, "Server rate limit exceeded");
|
|
|
|
/// <summary>
|
|
/// ctor
|
|
/// </summary>
|
|
public ServerRateLimitError(string? message = null, Exception? exception = null) : base(_errorInfo with { Message = (message?.Length > 0 ? _errorInfo.Message + ": " + message : _errorInfo.Message) }, exception) { }
|
|
|
|
/// <summary>
|
|
/// ctor
|
|
/// </summary>
|
|
protected ServerRateLimitError(ErrorInfo info, Exception? exception) : base(info, exception) { }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Cancellation requested
|
|
/// </summary>
|
|
public class CancellationRequestedError : Error
|
|
{
|
|
/// <summary>
|
|
/// Default error info
|
|
/// </summary>
|
|
protected static readonly ErrorInfo _errorInfo = new ErrorInfo(ErrorType.CancellationRequested, false, "Cancellation requested");
|
|
|
|
/// <summary>
|
|
/// ctor
|
|
/// </summary>
|
|
public CancellationRequestedError(Exception? exception = null) : base(null, _errorInfo, null) { }
|
|
|
|
/// <summary>
|
|
/// ctor
|
|
/// </summary>
|
|
protected CancellationRequestedError(ErrorInfo info, Exception? exception) : base(null, info, exception) { }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Invalid operation requested
|
|
/// </summary>
|
|
public class InvalidOperationError : Error
|
|
{
|
|
/// <summary>
|
|
/// Default error info
|
|
/// </summary>
|
|
protected static readonly ErrorInfo _errorInfo = new ErrorInfo(ErrorType.InvalidOperation, false, "Operation invalid");
|
|
|
|
/// <summary>
|
|
/// ctor
|
|
/// </summary>
|
|
public InvalidOperationError(string message) : base(null, _errorInfo with { Message = message }, null) { }
|
|
|
|
/// <summary>
|
|
/// ctor
|
|
/// </summary>
|
|
protected InvalidOperationError(ErrorInfo info, Exception? exception) : base(null, info, exception) { }
|
|
}
|
|
}
|