mirror of
https://github.com/JKorf/CryptoExchange.Net.git
synced 2026-08-11 16:32:57 +00:00
CryptoExchange V12 (#281)
* Result types: * (Web)CallResult types are replaced by HttpResult, WebSocketResult and QueryResult with the same logic * Updated result types to record type * Result creation can be done with (Http/WebSocket/Query)Result.Ok(..) and .Fail(..) * Removed implicit result type conversion to bool, `if (result)` no longer works, instead use `if (result.Success)` * Replaced CallResult.SuccessResult with CallResult.Ok() * Fixed result object nullability hinting, for example Data might be null if Success isn't checked for true * Parameters & serialization: * Added support for `enabled` and `disabled` strings to bool converter * Removed ParameterCollection type, has been replaced by Parameters type * Removed ArraySerialization, OrderParameters and ParameterOrderComparer properties from RestApiClient, moved to ParameterSerializationsSettings * Updated RestRequestConfiguration in AuthenticationProvider.ProcessRequest to contain the full RequestDefinition instead of copied fields * Clients: * Updated Api client constructor logging parameter from ILogger to ILoggerFactory? * Added Api client constructor exchange name parameter * Added ToString overrides on base API types * Added Exchange property on BaseApiClient * Added ApiCredentials property on IRestApiClient and ISocketApiClient interfaces * Updated ILogger source from client name to topic specific client name * Removed logging from client creation * Fixed BaseRestClient SetApiCredentials not marked as virtual * Rest: * Added BaseAddress to RequestDefinition object * Updated RestApiClient AuthenticationProvider logic from private to protected and virtual * Removed RestApiClient.SendAsync baseAddress parameter removed * Removed RestApiClient.SendAsync without type parameter * WebSocket: * Updated MessageRouting definition into CreateForEvent for subscriptions and CreateForQuery for queries * Improved Query type safety with CeateForQuery which allows second parameter for specifying the result type * Renamed MessageRouter.CreateWithoutHandler to CreateVoid * Updated SocketApiClient.GetSocketConnection to check connection uri instead of Tag for finding compatible connections * Removed unused UnhandledMessageExpected property SocketApiClient * Fixed issue in SocketApiClient.GetSocketConnection causing requests to always wait the full max 10 seconds when there was a reconnecting socket * Shared APIs: * Updated Option definitions to always require the exchange name as first parameter * Added missing dedicated option types * Added Discover method on ISharedClient interface, returning info on supported capabilities and operations * Added SharedRequest GetParamValue helper method accepting multiple parameter names * Added ResetStaticExchangeParameters method on ExchangeParameters * Added Status property to SharedWithdrawal model * Added TradingModes property to SharedBalance model * Updated ExchangeSymbolCache to support multiple environments and additional key separation * Updated Shared ExchangeParameters parameter names to be case insensitive * Updated code comments * Replaced ExchangeResult with ExchangeCallResult type * Removed AsExchangeResult/ExchangeWebResult * Removed TradingMode from the response model, only maintained on models where it makes sense * Removed IListenKey support, listen keys now rely on internal management with TokenManager * Rate limiting: * Fixed websocket connection attempts counting towards rate limit even when server could not be reached * Removed host from rate limit methods, now part of the already provided RequestDefinition * Added amount parameter to RateLimit Reset method to allow partially resetting the limit * Added TokenManager implementation for automatic listenkey/token management * Added UserClientProvider base class * Added async streaming on UserDataTracker items with StreamUpdatesAsync * Added cancellation token support to UserDataTracker starting * Added Unit type for non-result types * Added ServerError constructor taking ErrorType and message to make it easier to create * Added SupportedEnvironments property to PlatformInfo * Updated SymbolOrderBook DoResyncAsync to return CallResult instead of CallResult<bool> which was redundant * Various small performance improvements
This commit is contained in:
@@ -1,592 +0,0 @@
|
||||
using CryptoExchange.Net.SharedApis;
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text;
|
||||
|
||||
namespace CryptoExchange.Net.Objects
|
||||
{
|
||||
/// <summary>
|
||||
/// The result of an operation
|
||||
/// </summary>
|
||||
public class CallResult
|
||||
{
|
||||
/// <summary>
|
||||
/// Static success result
|
||||
/// </summary>
|
||||
public static CallResult SuccessResult { get; } = new CallResult(null);
|
||||
|
||||
/// <summary>
|
||||
/// An error if the call didn't succeed, will always be filled if Success = false
|
||||
/// </summary>
|
||||
public Error? Error { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether the call was successful
|
||||
/// </summary>
|
||||
public bool Success => Error == null;
|
||||
|
||||
/// <summary>
|
||||
/// ctor
|
||||
/// </summary>
|
||||
/// <param name="error"></param>
|
||||
public CallResult(Error? error)
|
||||
{
|
||||
Error = error;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overwrite bool check so we can use if(callResult) instead of if(callResult.Success)
|
||||
/// </summary>
|
||||
/// <param name="obj"></param>
|
||||
public static implicit operator bool(CallResult obj)
|
||||
{
|
||||
return obj?.Success == true;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
return Success ? $"Success" : $"Error: {Error}";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The result of an operation
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public class CallResult<T>: CallResult
|
||||
{
|
||||
/// <summary>
|
||||
/// The data returned by the call, only available when Success = true
|
||||
/// </summary>
|
||||
public T Data { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// The original data returned by the call, only available when `OutputOriginalData` is set to `true` in the client options
|
||||
/// </summary>
|
||||
public string? OriginalData { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// ctor
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
/// <param name="originalData"></param>
|
||||
/// <param name="error"></param>
|
||||
#pragma warning disable 8618
|
||||
public CallResult([AllowNull]T data, string? originalData, Error? error): base(error)
|
||||
#pragma warning restore 8618
|
||||
{
|
||||
OriginalData = originalData;
|
||||
#pragma warning disable 8601
|
||||
Data = data;
|
||||
#pragma warning restore 8601
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new data result
|
||||
/// </summary>
|
||||
/// <param name="data">The data to return</param>
|
||||
public CallResult(T data) : this(data, null, null) { }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new error result
|
||||
/// </summary>
|
||||
/// <param name="error">The error to return</param>
|
||||
public CallResult(Error error) : this(default, null, error) { }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new error result
|
||||
/// </summary>
|
||||
/// <param name="error">The error to return</param>
|
||||
/// <param name="originalData">The original response data</param>
|
||||
public CallResult(Error error, string? originalData) : this(default, originalData, error) { }
|
||||
|
||||
/// <summary>
|
||||
/// Overwrite bool check so we can use if(callResult) instead of if(callResult.Success)
|
||||
/// </summary>
|
||||
/// <param name="obj"></param>
|
||||
public static implicit operator bool(CallResult<T> obj)
|
||||
{
|
||||
return obj?.Success == true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether the call was successful or not. Useful for nullability checking.
|
||||
/// </summary>
|
||||
/// <param name="data">The data returned by the call.</param>
|
||||
/// <param name="error"><see cref="Error"/> on failure.</param>
|
||||
/// <returns><c>true</c> when <see cref="CallResult{T}"/> succeeded, <c>false</c> otherwise.</returns>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copy the WebCallResult to a new data type
|
||||
/// </summary>
|
||||
/// <typeparam name="K">The new type</typeparam>
|
||||
/// <param name="data">The data of the new type</param>
|
||||
/// <returns></returns>
|
||||
public CallResult<K> As<K>([AllowNull] K data)
|
||||
{
|
||||
return new CallResult<K>(data, OriginalData, Error);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copy as a dataless result
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public CallResult AsDataless()
|
||||
{
|
||||
if (Error != null )
|
||||
return new CallResult(Error);
|
||||
|
||||
return SuccessResult;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copy as a dataless result
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public CallResult AsDatalessError(Error error)
|
||||
{
|
||||
return new CallResult(error);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copy the CallResult to a new data type
|
||||
/// </summary>
|
||||
/// <typeparam name="K">The new type</typeparam>
|
||||
/// <param name="data">The data</param>
|
||||
/// <param name="error">The error returned</param>
|
||||
/// <returns></returns>
|
||||
public CallResult<K> AsErrorWithData<K>(Error error, K data)
|
||||
{
|
||||
return new CallResult<K>(data, OriginalData, error);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copy the WebCallResult to a new data type
|
||||
/// </summary>
|
||||
/// <typeparam name="K">The new type</typeparam>
|
||||
/// <param name="error">The error to return</param>
|
||||
/// <returns></returns>
|
||||
public CallResult<K> AsError<K>(Error error)
|
||||
{
|
||||
return new CallResult<K>(default, OriginalData, error);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
return Success ? $"Success" : $"Error: {Error}";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The result of a request
|
||||
/// </summary>
|
||||
public class WebCallResult : CallResult
|
||||
{
|
||||
/// <summary>
|
||||
/// The request http method
|
||||
/// </summary>
|
||||
public HttpMethod? RequestMethod { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// HTTP protocol version
|
||||
/// </summary>
|
||||
public Version? HttpVersion { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The headers sent with the request
|
||||
/// </summary>
|
||||
public HttpRequestHeaders? RequestHeaders { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The request id
|
||||
/// </summary>
|
||||
public int? RequestId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The url which was requested
|
||||
/// </summary>
|
||||
public string? RequestUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The body of the request
|
||||
/// </summary>
|
||||
public string? RequestBody { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The original data returned by the call, only available when `OutputOriginalData` is set to `true` in the client options
|
||||
/// </summary>
|
||||
public string? OriginalData { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// The status code of the response. Note that a OK status does not always indicate success, check the Success parameter for this.
|
||||
/// </summary>
|
||||
public HttpStatusCode? ResponseStatusCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The response headers
|
||||
/// </summary>
|
||||
public HttpResponseHeaders? ResponseHeaders { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The time between sending the request and receiving the response
|
||||
/// </summary>
|
||||
public TimeSpan? ResponseTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// ctor
|
||||
/// </summary>
|
||||
public WebCallResult(
|
||||
HttpStatusCode? code,
|
||||
Version? httpVersion,
|
||||
HttpResponseHeaders? responseHeaders,
|
||||
TimeSpan? responseTime,
|
||||
string? originalData,
|
||||
int? requestId,
|
||||
string? requestUrl,
|
||||
string? requestBody,
|
||||
HttpMethod? requestMethod,
|
||||
HttpRequestHeaders? requestHeaders,
|
||||
Error? error) : base(error)
|
||||
{
|
||||
ResponseStatusCode = code;
|
||||
HttpVersion = httpVersion;
|
||||
ResponseHeaders = responseHeaders;
|
||||
ResponseTime = responseTime;
|
||||
RequestId = requestId;
|
||||
OriginalData = originalData;
|
||||
|
||||
RequestUrl = requestUrl;
|
||||
RequestBody = requestBody;
|
||||
RequestHeaders = requestHeaders;
|
||||
RequestMethod = requestMethod;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ctor
|
||||
/// </summary>
|
||||
/// <param name="error"></param>
|
||||
public WebCallResult(Error error): base(error) { }
|
||||
|
||||
/// <summary>
|
||||
/// Return the result as an error result
|
||||
/// </summary>
|
||||
/// <param name="error">The error returned</param>
|
||||
/// <returns></returns>
|
||||
public WebCallResult AsError(Error error)
|
||||
{
|
||||
return new WebCallResult(ResponseStatusCode, HttpVersion, ResponseHeaders, ResponseTime, OriginalData, RequestId, RequestUrl, RequestBody, RequestMethod, RequestHeaders, error);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copy the WebCallResult to a new data type
|
||||
/// </summary>
|
||||
/// <typeparam name="K">The new type</typeparam>
|
||||
/// <param name="data">The data of the new type</param>
|
||||
/// <returns></returns>
|
||||
public WebCallResult<K> As<K>([AllowNull] K data)
|
||||
{
|
||||
return new WebCallResult<K>(ResponseStatusCode, HttpVersion, ResponseHeaders, ResponseTime, 0, null, RequestId, RequestUrl, RequestBody, RequestMethod, RequestHeaders, ResultDataSource.Server, data, Error);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copy the WebCallResult to an ExchangeWebResult of a new data type
|
||||
/// </summary>
|
||||
/// <typeparam name="K">The new type</typeparam>
|
||||
/// <param name="exchange">The exchange</param>
|
||||
/// <param name="tradeMode">Trade mode the result applies to</param>
|
||||
/// <param name="data">The data</param>
|
||||
/// <returns></returns>
|
||||
public ExchangeWebResult<K> AsExchangeResult<K>(string exchange, TradingMode tradeMode, [AllowNull] K data)
|
||||
{
|
||||
return new ExchangeWebResult<K>(exchange, tradeMode, this.As<K>(data));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copy the WebCallResult to an ExchangeWebResult of a new data type
|
||||
/// </summary>
|
||||
/// <typeparam name="K">The new type</typeparam>
|
||||
/// <param name="exchange">The exchange</param>
|
||||
/// <param name="tradeModes">Trade modes the result applies to</param>
|
||||
/// <param name="data">The data</param>
|
||||
/// <returns></returns>
|
||||
public ExchangeWebResult<K> AsExchangeResult<K>(string exchange, TradingMode[]? tradeModes, [AllowNull] K data)
|
||||
{
|
||||
return new ExchangeWebResult<K>(exchange, tradeModes, this.As<K>(data));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copy the WebCallResult to a new data type
|
||||
/// </summary>
|
||||
/// <typeparam name="K">The new type</typeparam>
|
||||
/// <param name="error">The error returned</param>
|
||||
/// <returns></returns>
|
||||
public WebCallResult<K> AsError<K>(Error error)
|
||||
{
|
||||
return new WebCallResult<K>(ResponseStatusCode, HttpVersion, ResponseHeaders, ResponseTime, 0, null, RequestId, RequestUrl, RequestBody, RequestMethod, RequestHeaders, ResultDataSource.Server, default, error);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
return (Success ? $"Success" : $"Error: {Error}") + $" in {ResponseTime}";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The result of a request
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public class WebCallResult<T>: CallResult<T>
|
||||
{
|
||||
/// <summary>
|
||||
/// The request http method
|
||||
/// </summary>
|
||||
public HttpMethod? RequestMethod { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// HTTP protocol version
|
||||
/// </summary>
|
||||
public Version? HttpVersion { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The headers sent with the request
|
||||
/// </summary>
|
||||
public HttpRequestHeaders? RequestHeaders { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The request id
|
||||
/// </summary>
|
||||
public int? RequestId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The url which was requested
|
||||
/// </summary>
|
||||
public string? RequestUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The body of the request
|
||||
/// </summary>
|
||||
public string? RequestBody { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The status code of the response. Note that a OK status does not always indicate success, check the Success parameter for this.
|
||||
/// </summary>
|
||||
public HttpStatusCode? ResponseStatusCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Length in bytes of the response
|
||||
/// </summary>
|
||||
public long? ResponseLength { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The response headers
|
||||
/// </summary>
|
||||
public HttpResponseHeaders? ResponseHeaders { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The time between sending the request and receiving the response
|
||||
/// </summary>
|
||||
public TimeSpan? ResponseTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The data source of this result
|
||||
/// </summary>
|
||||
public ResultDataSource DataSource { get; set; } = ResultDataSource.Server;
|
||||
|
||||
/// <summary>
|
||||
/// Create a new result
|
||||
/// </summary>
|
||||
public WebCallResult(
|
||||
HttpStatusCode? code,
|
||||
Version? httpVersion,
|
||||
HttpResponseHeaders? responseHeaders,
|
||||
TimeSpan? responseTime,
|
||||
long? responseLength,
|
||||
string? originalData,
|
||||
int? requestId,
|
||||
string? requestUrl,
|
||||
string? requestBody,
|
||||
HttpMethod? requestMethod,
|
||||
HttpRequestHeaders? requestHeaders,
|
||||
ResultDataSource dataSource,
|
||||
[AllowNull] T data,
|
||||
Error? error) : base(data, originalData, error)
|
||||
{
|
||||
HttpVersion = httpVersion;
|
||||
ResponseStatusCode = code;
|
||||
ResponseHeaders = responseHeaders;
|
||||
ResponseTime = responseTime;
|
||||
ResponseLength = responseLength;
|
||||
|
||||
RequestId = requestId;
|
||||
RequestUrl = requestUrl;
|
||||
RequestBody = requestBody;
|
||||
RequestHeaders = requestHeaders;
|
||||
RequestMethod = requestMethod;
|
||||
DataSource = dataSource;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copy as a dataless result
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public new WebCallResult AsDataless()
|
||||
{
|
||||
return new WebCallResult(ResponseStatusCode, HttpVersion, ResponseHeaders, ResponseTime, OriginalData, RequestId, RequestUrl, RequestBody, RequestMethod, RequestHeaders, Error);
|
||||
}
|
||||
/// <summary>
|
||||
/// Copy as a dataless result
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public new WebCallResult AsDatalessError(Error error)
|
||||
{
|
||||
return new WebCallResult(ResponseStatusCode, HttpVersion, ResponseHeaders, ResponseTime, OriginalData, RequestId, RequestUrl, RequestBody, RequestMethod, RequestHeaders, error);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new error result
|
||||
/// </summary>
|
||||
/// <param name="error">The error</param>
|
||||
public WebCallResult(Error? error) : this(null, null, null, null, null, null, null, null, null, null, null, ResultDataSource.Server, default, error) { }
|
||||
|
||||
/// <summary>
|
||||
/// Copy the WebCallResult to a new data type
|
||||
/// </summary>
|
||||
/// <typeparam name="K">The new type</typeparam>
|
||||
/// <param name="data">The data of the new type</param>
|
||||
/// <returns></returns>
|
||||
public new WebCallResult<K> As<K>([AllowNull] K data)
|
||||
{
|
||||
return new WebCallResult<K>(ResponseStatusCode, HttpVersion, ResponseHeaders, ResponseTime, ResponseLength, OriginalData, RequestId, RequestUrl, RequestBody, RequestMethod, RequestHeaders, DataSource, data, Error);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copy the WebCallResult to a new data type
|
||||
/// </summary>
|
||||
/// <typeparam name="K">The new type</typeparam>
|
||||
/// <param name="error">The error returned</param>
|
||||
/// <returns></returns>
|
||||
public new WebCallResult<K> AsError<K>(Error error)
|
||||
{
|
||||
return new WebCallResult<K>(ResponseStatusCode, HttpVersion, ResponseHeaders, ResponseTime, ResponseLength, OriginalData, RequestId, RequestUrl, RequestBody, RequestMethod, RequestHeaders, DataSource, default, error);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copy the WebCallResult to a new data type
|
||||
/// </summary>
|
||||
/// <typeparam name="K">The new type</typeparam>
|
||||
/// <param name="data">The data</param>
|
||||
/// <param name="error">The error returned</param>
|
||||
/// <returns></returns>
|
||||
public new WebCallResult<K> AsErrorWithData<K>(Error error, K data)
|
||||
{
|
||||
return new WebCallResult<K>(ResponseStatusCode, HttpVersion, ResponseHeaders, ResponseTime, ResponseLength, OriginalData, RequestId, RequestUrl, RequestBody, RequestMethod, RequestHeaders, DataSource, data, error);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copy the WebCallResult to an ExchangeWebResult of a new data type
|
||||
/// </summary>
|
||||
/// <param name="exchange">The exchange</param>
|
||||
/// <param name="tradeMode">Trade mode the result applies to</param>
|
||||
/// <returns></returns>
|
||||
public ExchangeWebResult<T> AsExchangeResult(string exchange, TradingMode tradeMode)
|
||||
{
|
||||
return new ExchangeWebResult<T>(exchange, tradeMode, this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copy the WebCallResult to an ExchangeWebResult of a new data type
|
||||
/// </summary>
|
||||
/// <param name="exchange">The exchange</param>
|
||||
/// <param name="tradeModes">Trade modes the result applies to</param>
|
||||
/// <returns></returns>
|
||||
public ExchangeWebResult<T> AsExchangeResult(string exchange, TradingMode[] tradeModes)
|
||||
{
|
||||
return new ExchangeWebResult<T>(exchange, tradeModes, this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copy the WebCallResult to an ExchangeWebResult of a new data type
|
||||
/// </summary>
|
||||
/// <typeparam name="K">The new type</typeparam>
|
||||
/// <param name="exchange">The exchange</param>
|
||||
/// <param name="tradeMode">Trade mode the result applies to</param>
|
||||
/// <param name="data">Data</param>
|
||||
/// <param name="nextPageRequest">Next page request</param>
|
||||
/// <returns></returns>
|
||||
public ExchangeWebResult<K> AsExchangeResult<K>(string exchange, TradingMode tradeMode, [AllowNull] K data, PageRequest? nextPageRequest = null)
|
||||
{
|
||||
return new ExchangeWebResult<K>(exchange, tradeMode, As<K>(data), nextPageRequest);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copy the WebCallResult to an ExchangeWebResult of a new data type
|
||||
/// </summary>
|
||||
/// <typeparam name="K">The new type</typeparam>
|
||||
/// <param name="exchange">The exchange</param>
|
||||
/// <param name="tradeModes">Trade modes the result applies to</param>
|
||||
/// <param name="data">Data</param>
|
||||
/// <param name="nextPageRequest">Next page token</param>
|
||||
/// <returns></returns>
|
||||
public ExchangeWebResult<K> AsExchangeResult<K>(string exchange, TradingMode[]? tradeModes, [AllowNull] K data, PageRequest? nextPageRequest = null)
|
||||
{
|
||||
return new ExchangeWebResult<K>(exchange, tradeModes, As<K>(data), nextPageRequest);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copy the WebCallResult to an ExchangeWebResult with a specific error
|
||||
/// </summary>
|
||||
/// <typeparam name="K">The new type</typeparam>
|
||||
/// <param name="exchange">The exchange</param>
|
||||
/// <param name="error">The error returned</param>
|
||||
/// <returns></returns>
|
||||
public ExchangeWebResult<K> AsExchangeError<K>(string exchange, Error error)
|
||||
{
|
||||
return new ExchangeWebResult<K>(exchange, null, AsError<K>(error));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return a copy of this result with data source set to cache
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
internal WebCallResult<T> Cached()
|
||||
{
|
||||
return new WebCallResult<T>(ResponseStatusCode, HttpVersion, ResponseHeaders, ResponseTime, ResponseLength, OriginalData, RequestId, RequestUrl, RequestBody, RequestMethod, RequestHeaders, ResultDataSource.Cache, Data, Error);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
sb.Append(Success ? $"Success response" : $"Error response: {Error}");
|
||||
if (ResponseLength != null)
|
||||
sb.Append($", {ResponseLength} bytes");
|
||||
if (ResponseTime != null)
|
||||
sb.Append($", received in {Math.Round(ResponseTime?.TotalMilliseconds ?? 0)}ms");
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -149,6 +149,14 @@ namespace CryptoExchange.Net.Objects
|
||||
/// </summary>
|
||||
public class ServerError : Error
|
||||
{
|
||||
/// <summary>
|
||||
/// ctor
|
||||
/// </summary>
|
||||
public ServerError(ErrorType type, string message, Exception? exception = null)
|
||||
: base(null, new ErrorInfo(type, message), exception)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ctor
|
||||
/// </summary>
|
||||
|
||||
@@ -44,7 +44,7 @@ namespace CryptoExchange.Net.Objects.Options
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
return $"RequestTimeout: {RequestTimeout}, Proxy: {(Proxy == null ? "-" : "set")}";
|
||||
return $"Proxy: {(Proxy == null ? "-" : "set")}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,6 +105,12 @@ namespace CryptoExchange.Net.Objects.Options
|
||||
target.Environment = Environment;
|
||||
return target;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{base.ToString()} | Environment: {Environment.Name}";
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -131,7 +137,7 @@ namespace CryptoExchange.Net.Objects.Options
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{base.ToString()}, ApiCredentials: {(ApiCredentials == null ? "-" : "set")}";
|
||||
return $"{base.ToString()} | ApiCredentials: {(ApiCredentials == null ? "-" : "set")}";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -132,6 +132,12 @@ namespace CryptoExchange.Net.Objects.Options
|
||||
target.Environment = Environment;
|
||||
return target;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{base.ToString()} | Environment: {Environment.Name}";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -159,7 +165,7 @@ namespace CryptoExchange.Net.Objects.Options
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{base.ToString()}, ApiCredentials: {(ApiCredentials == null ? "-" : "set")}";
|
||||
return $"{base.ToString()} | ApiCredentials: {(ApiCredentials == null ? "-" : "set")}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,343 +0,0 @@
|
||||
using CryptoExchange.Net.Attributes;
|
||||
using CryptoExchange.Net.Converters.SystemTextJson;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
|
||||
namespace CryptoExchange.Net.Objects
|
||||
{
|
||||
/// <summary>
|
||||
/// Parameters collection
|
||||
/// </summary>
|
||||
public class ParameterCollection : Dictionary<string, object>
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public new void Add(string key, object value)
|
||||
{
|
||||
if (value == null)
|
||||
throw new ArgumentNullException(key);
|
||||
|
||||
base.Add(key, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add an optional parameter. Not added if value is null
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="value"></param>
|
||||
public void AddOptional(string key, object? value)
|
||||
{
|
||||
if (value != null)
|
||||
base.Add(key, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a decimal value as string
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="value"></param>
|
||||
public void AddString(string key, decimal value)
|
||||
{
|
||||
base.Add(key, value.ToString(CultureInfo.InvariantCulture));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a decimal value as string. Not added if value is null
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="value"></param>
|
||||
public void AddOptionalString(string key, decimal? value)
|
||||
{
|
||||
if (value != null)
|
||||
base.Add(key, value.Value.ToString(CultureInfo.InvariantCulture));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a int value as string
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="value"></param>
|
||||
public void AddString(string key, int value)
|
||||
{
|
||||
base.Add(key, value.ToString(CultureInfo.InvariantCulture));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a int value as string. Not added if value is null
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="value"></param>
|
||||
public void AddOptionalString(string key, int? value)
|
||||
{
|
||||
if (value != null)
|
||||
base.Add(key, value.Value.ToString(CultureInfo.InvariantCulture));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a long value as string
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="value"></param>
|
||||
public void AddString(string key, long value)
|
||||
{
|
||||
base.Add(key, value.ToString(CultureInfo.InvariantCulture));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a long value as string. Not added if value is null
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="value"></param>
|
||||
public void AddOptionalString(string key, long? value)
|
||||
{
|
||||
if (value != null)
|
||||
base.Add(key, value.Value.ToString(CultureInfo.InvariantCulture));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a DateTime value as string
|
||||
/// </summary>
|
||||
public void AddString(string key, DateTime value)
|
||||
{
|
||||
base.Add(key, value.ToString("yyyy-MM-ddTHH:mm:ssZ"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a DateTime value as string. Not added if value is null
|
||||
/// </summary>
|
||||
public void AddOptionalString(string key, DateTime? value)
|
||||
{
|
||||
if (value != null)
|
||||
base.Add(key, value.Value.ToString("yyyy-MM-ddTHH:mm:ssZ"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a datetime value as milliseconds timestamp
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="value"></param>
|
||||
public void AddMilliseconds(string key, DateTime value)
|
||||
{
|
||||
base.Add(key, DateTimeConverter.ConvertToMilliseconds(value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a datetime value as milliseconds timestamp. Not added if value is null
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="value"></param>
|
||||
public void AddOptionalMilliseconds(string key, DateTime? value)
|
||||
{
|
||||
if (value != null)
|
||||
base.Add(key, DateTimeConverter.ConvertToMilliseconds(value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a datetime value as milliseconds timestamp
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="value"></param>
|
||||
public void AddMillisecondsString(string key, DateTime value)
|
||||
{
|
||||
base.Add(key, DateTimeConverter.ConvertToMilliseconds(value).Value.ToString(CultureInfo.InvariantCulture));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a datetime value as milliseconds timestamp. Not added if value is null
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="value"></param>
|
||||
public void AddOptionalMillisecondsString(string key, DateTime? value)
|
||||
{
|
||||
if (value != null)
|
||||
base.Add(key, DateTimeConverter.ConvertToMilliseconds(value).Value.ToString(CultureInfo.InvariantCulture));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a datetime value as seconds timestamp
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="value"></param>
|
||||
public void AddSeconds(string key, DateTime value)
|
||||
{
|
||||
base.Add(key, DateTimeConverter.ConvertToSeconds(value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a datetime value as seconds timestamp. Not added if value is null
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="value"></param>
|
||||
public void AddOptionalSeconds(string key, DateTime? value)
|
||||
{
|
||||
if (value != null)
|
||||
base.Add(key, DateTimeConverter.ConvertToSeconds(value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a datetime value as string seconds timestamp
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="value"></param>
|
||||
public void AddSecondsString(string key, DateTime value)
|
||||
{
|
||||
base.Add(key, DateTimeConverter.ConvertToSeconds(value).ToString()!);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a datetime value as string seconds timestamp. Not added if value is null
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="value"></param>
|
||||
public void AddOptionalSecondsString(string key, DateTime? value)
|
||||
{
|
||||
if (value != null)
|
||||
base.Add(key, DateTimeConverter.ConvertToSeconds(value).ToString()!);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add an enum value as the string value as mapped using the <see cref="MapAttribute" />
|
||||
/// </summary>
|
||||
#if NET5_0_OR_GREATER
|
||||
public void AddEnum<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor | DynamicallyAccessedMemberTypes.PublicFields)] T>(string key, T value)
|
||||
#else
|
||||
public void AddEnum<T>(string key, T value)
|
||||
#endif
|
||||
where T : struct, Enum
|
||||
{
|
||||
base.Add(key, EnumConverter<T>.GetString(value)!);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add an enum value as the string value as mapped using the <see cref="MapAttribute" />
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="value"></param>
|
||||
#if NET5_0_OR_GREATER
|
||||
public void AddEnumAsInt<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor | DynamicallyAccessedMemberTypes.PublicFields)] T>(string key, T value)
|
||||
#else
|
||||
public void AddEnumAsInt<T>(string key, T value)
|
||||
#endif
|
||||
where T : struct, Enum
|
||||
{
|
||||
var stringVal = EnumConverter<T>.GetString(value)!;
|
||||
base.Add(key, int.Parse(stringVal)!);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add an enum value as the string value as mapped using the <see cref="MapAttribute" />. Not added if value is null
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="value"></param>
|
||||
#if NET5_0_OR_GREATER
|
||||
public void AddOptionalEnum<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor | DynamicallyAccessedMemberTypes.PublicFields)] T>(string key, T? value)
|
||||
#else
|
||||
public void AddOptionalEnum<T>(string key, T? value)
|
||||
#endif
|
||||
where T : struct, Enum
|
||||
{
|
||||
if (value != null)
|
||||
base.Add(key, EnumConverter<T>.GetString(value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add an enum value as the string value as mapped using the <see cref="MapAttribute" />. Not added if value is null
|
||||
/// </summary>
|
||||
#if NET5_0_OR_GREATER
|
||||
public void AddOptionalEnumAsInt<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor | DynamicallyAccessedMemberTypes.PublicFields)] T>(string key, T? value)
|
||||
#else
|
||||
public void AddOptionalEnumAsInt<T>(string key, T? value)
|
||||
#endif
|
||||
where T : struct, Enum
|
||||
{
|
||||
if (value != null)
|
||||
{
|
||||
var stringVal = EnumConverter<T>.GetString(value);
|
||||
base.Add(key, int.Parse(stringVal));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add key as comma separated values
|
||||
/// </summary>
|
||||
public void AddCommaSeparated(string key, IEnumerable<string> values)
|
||||
{
|
||||
base.Add(key, string.Join(",", values));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add key as comma separated values if there are values provided
|
||||
/// </summary>
|
||||
public void AddOptionalCommaSeparated(string key, IEnumerable<string>? values)
|
||||
{
|
||||
if (values == null || !values.Any())
|
||||
return;
|
||||
|
||||
base.Add(key, string.Join(",", values));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add key as comma separated values
|
||||
/// </summary>
|
||||
#if NET5_0_OR_GREATER
|
||||
public void AddCommaSeparated<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor | DynamicallyAccessedMemberTypes.PublicFields)] T>(string key, IEnumerable<T> values)
|
||||
#else
|
||||
public void AddCommaSeparated<T>(string key, IEnumerable<T> values)
|
||||
#endif
|
||||
where T : struct, Enum
|
||||
{
|
||||
base.Add(key, string.Join(",", values.Select(x => EnumConverter.GetString(x))));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add key as comma separated values if there are values provided
|
||||
/// </summary>
|
||||
#if NET5_0_OR_GREATER
|
||||
public void AddOptionalCommaSeparated<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor | DynamicallyAccessedMemberTypes.PublicFields)] T>(string key, IEnumerable<T>? values)
|
||||
#else
|
||||
public void AddOptionalCommaSeparated<T>(string key, IEnumerable<T>? values)
|
||||
#endif
|
||||
where T : struct, Enum
|
||||
{
|
||||
if (values == null || !values.Any())
|
||||
return;
|
||||
|
||||
base.Add(key, string.Join(",", values.Select(x => EnumConverter.GetString(x))));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add key as boolean lower case value
|
||||
/// </summary>
|
||||
public void AddBoolString(string key, bool value)
|
||||
{
|
||||
base.Add(key, value.ToString().ToLower());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add key as boolean lower case value if it's not null
|
||||
/// </summary>
|
||||
public void AddOptionalBoolString(string key, bool? value)
|
||||
{
|
||||
if (value == null)
|
||||
return;
|
||||
|
||||
base.Add(key, value.ToString()!.ToLower());
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Set the request body. Can be used to specify a simple value or array as the body instead of an object
|
||||
/// </summary>
|
||||
/// <param name="body">Body to set</param>
|
||||
/// <exception cref="InvalidOperationException"></exception>
|
||||
public void SetBody(object body)
|
||||
{
|
||||
if (this.Any())
|
||||
throw new InvalidOperationException("Can't set body when other parameters already specified");
|
||||
|
||||
base.Add(Constants.BodyPlaceHolderKey, body);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace CryptoExchange.Net.Objects
|
||||
{
|
||||
/// <summary>
|
||||
/// Settings for parameter serialization
|
||||
/// </summary>
|
||||
public class ParameterSerializationSettings
|
||||
{
|
||||
/// <summary>
|
||||
/// Default serialization settings
|
||||
/// </summary>
|
||||
public static ParameterSerializationSettings Default { get; } = new ParameterSerializationSettings();
|
||||
|
||||
/// <summary>
|
||||
/// Whether to sort the parameters
|
||||
/// </summary>
|
||||
public bool Sort { get; set; } = true;
|
||||
/// <summary>
|
||||
/// The parameter comparer when sorting
|
||||
/// </summary>
|
||||
public IComparer<string>? SortComparer { get; set; }
|
||||
/// <summary>
|
||||
/// Decimal serialization type
|
||||
/// </summary>
|
||||
public DecimalSerialization Decimal { get; set; } = DecimalSerialization.Number;
|
||||
/// <summary>
|
||||
/// DateTime serialization type
|
||||
/// </summary>
|
||||
public DateTimeSerialization DateTimes { get; set; } = DateTimeSerialization.MillisecondsNumber;
|
||||
/// <summary>
|
||||
/// Boolean serialization type
|
||||
/// </summary>
|
||||
public BoolSerialization Bool { get; set; } = BoolSerialization.Bool;
|
||||
/// <summary>
|
||||
/// Integer serialization type
|
||||
/// </summary>
|
||||
public IntegerSerialization Integer { get; set; } = IntegerSerialization.Number;
|
||||
/// <summary>
|
||||
/// Enum serialization type
|
||||
/// </summary>
|
||||
public EnumSerialization Enum { get; set; } = EnumSerialization.String;
|
||||
/// <summary>
|
||||
/// Array serialization type
|
||||
/// </summary>
|
||||
public ArrayParametersSerialization Array { get; set; } = ArrayParametersSerialization.Array;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Type of decimal value serialization
|
||||
/// </summary>
|
||||
public enum DecimalSerialization
|
||||
{
|
||||
/// <summary>
|
||||
/// Decimals should be serialized as numbers
|
||||
/// </summary>
|
||||
Number,
|
||||
/// <summary>
|
||||
/// Decimals should be strings
|
||||
/// </summary>
|
||||
String
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Type of DateTime value serialization
|
||||
/// </summary>
|
||||
public enum DateTimeSerialization
|
||||
{
|
||||
/// <summary>
|
||||
/// DateTimes should be serialized as milliseconds number
|
||||
/// </summary>
|
||||
MillisecondsNumber,
|
||||
/// <summary>
|
||||
/// DateTimes should be serialized as milliseconds string
|
||||
/// </summary>
|
||||
MillisecondsString,
|
||||
/// <summary>
|
||||
/// DateTimes should be serialized as seconds number
|
||||
/// </summary>
|
||||
SecondsNumber,
|
||||
/// <summary>
|
||||
/// DateTimes should be serialized as seconds string
|
||||
/// </summary>
|
||||
SecondsString,
|
||||
/// <summary>
|
||||
/// DateTimes should be serialized as microseconds number
|
||||
/// </summary>
|
||||
MicrosecondsNumber,
|
||||
/// <summary>
|
||||
/// DateTimes should be serialized as microseconds string
|
||||
/// </summary>
|
||||
MicrosecondsString,
|
||||
/// <summary>
|
||||
/// DateTimes should be serialized as ISO 8601 string
|
||||
/// </summary>
|
||||
Rfc3339String
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Type of boolean value serialization
|
||||
/// </summary>
|
||||
public enum BoolSerialization
|
||||
{
|
||||
/// <summary>
|
||||
/// Booleans should be serialized as bool values
|
||||
/// </summary>
|
||||
Bool,
|
||||
/// <summary>
|
||||
/// Booleans should be serialized as strings
|
||||
/// </summary>
|
||||
String
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Type of integer value serialization
|
||||
/// </summary>
|
||||
public enum IntegerSerialization
|
||||
{
|
||||
/// <summary>
|
||||
/// Integers should be serialized as integer values
|
||||
/// </summary>
|
||||
Number,
|
||||
/// <summary>
|
||||
/// Integers should be serialized as strings
|
||||
/// </summary>
|
||||
String
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Type of enum value serialization
|
||||
/// </summary>
|
||||
public enum EnumSerialization
|
||||
{
|
||||
/// <summary>
|
||||
/// Enums should be serialized as integer values
|
||||
/// </summary>
|
||||
Number,
|
||||
/// <summary>
|
||||
/// Enums should be serialized as strings
|
||||
/// </summary>
|
||||
String
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,375 @@
|
||||
using CryptoExchange.Net.Attributes;
|
||||
using CryptoExchange.Net.Converters.SystemTextJson;
|
||||
using CryptoExchange.Net.Interfaces;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
|
||||
namespace CryptoExchange.Net.Objects
|
||||
{
|
||||
/// <summary>
|
||||
/// Set of parameters
|
||||
/// </summary>
|
||||
public class Parameters : IDictionary<string, object>
|
||||
{
|
||||
private readonly ParameterSerializationSettings _serializationSettings;
|
||||
private IDictionary<string, object> _parameters;
|
||||
private object? _value;
|
||||
|
||||
/// <inheritdoc />
|
||||
public object? BodyValue => _value;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ICollection<string> Keys => _parameters.Keys;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ICollection<object> Values => _parameters.Values;
|
||||
|
||||
/// <inheritdoc />
|
||||
public int Count => _parameters.Count;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsReadOnly => _parameters.IsReadOnly;
|
||||
|
||||
/// <summary>
|
||||
/// Whether any parameters are defined
|
||||
/// </summary>
|
||||
public bool Empty => _parameters.Count == 0 && _value == null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public object this[string key] { get => _parameters[key]; set => _parameters[key] = value; }
|
||||
|
||||
/// <summary>
|
||||
/// ctor
|
||||
/// </summary>
|
||||
/// <param name="serializationSettings">Serialization settings</param>
|
||||
public Parameters(ParameterSerializationSettings serializationSettings)
|
||||
{
|
||||
_serializationSettings = serializationSettings;
|
||||
if (_serializationSettings.Sort)
|
||||
_parameters = new SortedDictionary<string, object>(_serializationSettings.SortComparer);
|
||||
else
|
||||
_parameters = new Dictionary<string, object>();
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ctor
|
||||
/// </summary>
|
||||
/// <param name="serializationSettings">Serialization settings</param>
|
||||
/// <param name="value">Body value</param>
|
||||
public Parameters(object value, ParameterSerializationSettings serializationSettings)
|
||||
{
|
||||
_parameters = new Dictionary<string, object>();
|
||||
_serializationSettings = serializationSettings;
|
||||
_value = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a short value if it is not null
|
||||
/// </summary>
|
||||
public void Add(string key, short? value, IntegerSerialization? serialization = null)
|
||||
{
|
||||
if (value == null)
|
||||
return;
|
||||
|
||||
Add(key, value.Value, serialization);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a short value
|
||||
/// </summary>
|
||||
public void Add(string key, short value, IntegerSerialization? serialization = null)
|
||||
{
|
||||
var serializationToUse = serialization ?? _serializationSettings.Integer;
|
||||
if (serializationToUse == IntegerSerialization.String)
|
||||
_parameters.Add(key, value.ToString(CultureInfo.InvariantCulture));
|
||||
else if (serializationToUse == IntegerSerialization.Number)
|
||||
_parameters.Add(key, value);
|
||||
else
|
||||
throw new ArgumentException("Unknown Integer serialization setting");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add an int value if it is not null
|
||||
/// </summary>
|
||||
public void Add(string key, int? value, IntegerSerialization? serialization = null)
|
||||
{
|
||||
if (value == null)
|
||||
return;
|
||||
|
||||
Add(key, value.Value, serialization);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add an int value
|
||||
/// </summary>
|
||||
public void Add(string key, int value, IntegerSerialization? serialization = null)
|
||||
{
|
||||
var serializationToUse = serialization ?? _serializationSettings.Integer;
|
||||
if (serializationToUse == IntegerSerialization.String)
|
||||
_parameters.Add(key, value.ToString(CultureInfo.InvariantCulture));
|
||||
else if (serializationToUse == IntegerSerialization.Number)
|
||||
_parameters.Add(key, value);
|
||||
else
|
||||
throw new ArgumentException("Unknown Integer serialization setting");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a long value if it is not null
|
||||
/// </summary>
|
||||
public void Add(string key, long? value, IntegerSerialization? serialization = null)
|
||||
{
|
||||
if (value == null)
|
||||
return;
|
||||
|
||||
Add(key, value.Value, serialization);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a long value
|
||||
/// </summary>
|
||||
public void Add(string key, long value, IntegerSerialization? serialization = null)
|
||||
{
|
||||
var serializationToUse = serialization ?? _serializationSettings.Integer;
|
||||
if (serializationToUse == IntegerSerialization.String)
|
||||
_parameters.Add(key, value.ToString(CultureInfo.InvariantCulture));
|
||||
else if (serializationToUse == IntegerSerialization.Number)
|
||||
_parameters.Add(key, value);
|
||||
else
|
||||
throw new ArgumentException("Unknown Integer serialization setting");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a decimal value if it is not null
|
||||
/// </summary>
|
||||
public void Add(string key, decimal? value, DecimalSerialization? serialization = null)
|
||||
{
|
||||
if (value == null)
|
||||
return;
|
||||
|
||||
Add(key, value.Value, serialization);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a decimal value
|
||||
/// </summary>
|
||||
public void Add(string key, decimal value, DecimalSerialization? serialization = null)
|
||||
{
|
||||
var serializationToUse = serialization ?? _serializationSettings.Decimal;
|
||||
if (serializationToUse == DecimalSerialization.String)
|
||||
_parameters.Add(key, value.ToString(CultureInfo.InvariantCulture));
|
||||
else if (serializationToUse == DecimalSerialization.Number)
|
||||
_parameters.Add(key, value);
|
||||
else
|
||||
throw new ArgumentException("Unknown Decimal serialization setting");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a double value if it is not null
|
||||
/// </summary>
|
||||
public void Add(string key, double? value, DecimalSerialization? serialization = null)
|
||||
{
|
||||
if (value == null)
|
||||
return;
|
||||
|
||||
Add(key, value.Value, serialization);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a double value
|
||||
/// </summary>
|
||||
public void Add(string key, double value, DecimalSerialization? serialization = null)
|
||||
{
|
||||
var serializationToUse = serialization ?? _serializationSettings.Decimal;
|
||||
if (serializationToUse == DecimalSerialization.String)
|
||||
_parameters.Add(key, value.ToString(CultureInfo.InvariantCulture));
|
||||
else if (serializationToUse == DecimalSerialization.Number)
|
||||
_parameters.Add(key, value);
|
||||
else
|
||||
throw new ArgumentException("Unknown Decimal serialization setting");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a bool value if it is not null
|
||||
/// </summary>
|
||||
public void Add(string key, bool? value, BoolSerialization? serialization = null)
|
||||
{
|
||||
if (value == null)
|
||||
return;
|
||||
|
||||
Add(key, value.Value, serialization);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a bool value
|
||||
/// </summary>
|
||||
public void Add(string key, bool value, BoolSerialization? serialization = null)
|
||||
{
|
||||
var serializationToUse = serialization ?? _serializationSettings.Bool;
|
||||
if (serializationToUse == BoolSerialization.String)
|
||||
_parameters.Add(key, value.ToString(CultureInfo.InvariantCulture).ToLowerInvariant());
|
||||
else if (serializationToUse == BoolSerialization.Bool)
|
||||
_parameters.Add(key, value);
|
||||
else
|
||||
throw new ArgumentException("Unknown Bool serialization setting");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add key as comma separated values if there are values provided
|
||||
/// </summary>
|
||||
public void AddCommaSeparated(string key, IEnumerable<string>? values)
|
||||
{
|
||||
if (values == null || !values.Any())
|
||||
return;
|
||||
|
||||
_parameters.Add(key, string.Join(",", values));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add key as comma separated values
|
||||
/// </summary>
|
||||
#if NET5_0_OR_GREATER
|
||||
public void AddCommaSeparated<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor | DynamicallyAccessedMemberTypes.PublicFields)] T>(string key, IEnumerable<T> values)
|
||||
#else
|
||||
public void AddCommaSeparated<T>(string key, IEnumerable<T>? values)
|
||||
#endif
|
||||
where T : struct, Enum
|
||||
{
|
||||
if (values == null || !values.Any())
|
||||
return;
|
||||
|
||||
_parameters.Add(key, string.Join(",", values.Select(x => EnumConverter.GetString(x))));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add an enum value if it is not null
|
||||
/// </summary>
|
||||
public void Add<
|
||||
#if NET5_0_OR_GREATER
|
||||
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor | DynamicallyAccessedMemberTypes.PublicFields)]
|
||||
# endif
|
||||
T>(string key, T? value, EnumSerialization? serialization = null)
|
||||
where T : struct, Enum
|
||||
|
||||
{
|
||||
if (value == null)
|
||||
return;
|
||||
|
||||
Add(key, value.Value, serialization);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a enum value
|
||||
/// </summary>
|
||||
public void Add<
|
||||
#if NET5_0_OR_GREATER
|
||||
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor | DynamicallyAccessedMemberTypes.PublicFields)]
|
||||
#endif
|
||||
T>(string key, T value, EnumSerialization? serialization = null)
|
||||
where T : struct, Enum
|
||||
{
|
||||
var serializationToUse = serialization ?? _serializationSettings.Enum;
|
||||
if (serializationToUse == EnumSerialization.String)
|
||||
_parameters.Add(key, EnumConverter<T>.GetString(value));
|
||||
else if (serializationToUse == EnumSerialization.Number)
|
||||
_parameters.Add(key, int.Parse(EnumConverter<T>.GetString(value), CultureInfo.InvariantCulture));
|
||||
else
|
||||
throw new ArgumentException("Unknown Integer serialization setting");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a DateTime value if it is not null
|
||||
/// </summary>
|
||||
public void Add(string key, DateTime? value, DateTimeSerialization? serialization = null)
|
||||
{
|
||||
if (value == null)
|
||||
return;
|
||||
|
||||
Add(key, value.Value, serialization);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a DateTime value
|
||||
/// </summary>
|
||||
public void Add(string key, DateTime value, DateTimeSerialization? serialization = null)
|
||||
{
|
||||
var serializationToUse = serialization ?? _serializationSettings.DateTimes;
|
||||
if (serializationToUse == DateTimeSerialization.MillisecondsNumber)
|
||||
_parameters.Add(key, DateTimeConverter.ConvertToMilliseconds(value));
|
||||
else if (serializationToUse == DateTimeSerialization.MillisecondsString)
|
||||
_parameters.Add(key, DateTimeConverter.ConvertToMilliseconds(value).Value.ToString(CultureInfo.InvariantCulture));
|
||||
else if (serializationToUse == DateTimeSerialization.SecondsNumber)
|
||||
_parameters.Add(key, DateTimeConverter.ConvertToSeconds(value));
|
||||
else if (serializationToUse == DateTimeSerialization.SecondsString)
|
||||
_parameters.Add(key, DateTimeConverter.ConvertToSeconds(value).Value.ToString(CultureInfo.InvariantCulture));
|
||||
else if (serializationToUse == DateTimeSerialization.MicrosecondsNumber)
|
||||
_parameters.Add(key, DateTimeConverter.ConvertToMicroseconds(value));
|
||||
else if (serializationToUse == DateTimeSerialization.MicrosecondsString)
|
||||
_parameters.Add(key, DateTimeConverter.ConvertToMicroseconds(value).Value.ToString(CultureInfo.InvariantCulture));
|
||||
else if (serializationToUse == DateTimeSerialization.Rfc3339String)
|
||||
_parameters.Add(key, value.ToRfc3339String());
|
||||
else
|
||||
throw new ArgumentException("Unknown DateTime serialization setting");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a string value if it is not null
|
||||
/// </summary>
|
||||
public void Add(string key, string? value)
|
||||
{
|
||||
if (value == null)
|
||||
return;
|
||||
|
||||
_parameters.Add(key, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add an array of values if there are values provided
|
||||
/// </summary>
|
||||
public void AddArray<T>(string key, IEnumerable<T>? values)
|
||||
{
|
||||
if (values == null || !values.Any())
|
||||
return;
|
||||
|
||||
_parameters.Add(key, values is T[] arr ? arr : values.ToArray());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a raw object value if it is not null
|
||||
/// </summary>
|
||||
public void AddRaw(string key, object? value)
|
||||
{
|
||||
if (value == null)
|
||||
return;
|
||||
|
||||
_parameters.Add(key, value);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Add(string key, object value) => _parameters.Add(key, value);
|
||||
/// <inheritdoc />
|
||||
public bool ContainsKey(string key) => _parameters.ContainsKey(key);
|
||||
/// <inheritdoc />
|
||||
public bool Remove(string key) => _parameters.Remove(key);
|
||||
/// <inheritdoc />
|
||||
public bool TryGetValue(string key, out object value) => _parameters.TryGetValue(key, out value!);
|
||||
/// <inheritdoc />
|
||||
public void Add(KeyValuePair<string, object> item) => _parameters.Add(item.Key, item.Value);
|
||||
/// <inheritdoc />
|
||||
public void Clear() => _parameters.Clear();
|
||||
/// <inheritdoc />
|
||||
public bool Contains(KeyValuePair<string, object> item) => _parameters.ContainsKey(item.Key) && _parameters[item.Key] == item.Value;
|
||||
/// <inheritdoc />
|
||||
public void CopyTo(KeyValuePair<string, object>[] array, int arrayIndex) => _parameters.CopyTo(array, arrayIndex);
|
||||
/// <inheritdoc />
|
||||
public bool Remove(KeyValuePair<string, object> item) => _parameters.Remove(item.Key);
|
||||
/// <inheritdoc />
|
||||
public IEnumerator<KeyValuePair<string, object>> GetEnumerator() => _parameters.GetEnumerator();
|
||||
/// <inheritdoc />
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
}
|
||||
}
|
||||
@@ -33,11 +33,23 @@
|
||||
/// Centralization type
|
||||
/// </summary>
|
||||
public CentralizationType CentralizationType { get; }
|
||||
/// <summary>
|
||||
/// Supported environments
|
||||
/// </summary>
|
||||
public string[] SupportedEnvironments { get; }
|
||||
|
||||
/// <summary>
|
||||
/// ctor
|
||||
/// </summary>
|
||||
public PlatformInfo(string id, string displayName, string logo, string url, string[] apiDocsUrl, PlatformType platformType, CentralizationType centralizationType)
|
||||
public PlatformInfo(
|
||||
string id,
|
||||
string displayName,
|
||||
string logo,
|
||||
string url,
|
||||
string[] apiDocsUrl,
|
||||
PlatformType platformType,
|
||||
CentralizationType centralizationType,
|
||||
string[] supportedEnvironments)
|
||||
{
|
||||
Id = id;
|
||||
DisplayName = displayName;
|
||||
@@ -46,6 +58,7 @@
|
||||
ApiDocsUrl = apiDocsUrl;
|
||||
PlatformType = platformType;
|
||||
CentralizationType = centralizationType;
|
||||
SupportedEnvironments = supportedEnvironments;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,9 +9,14 @@ namespace CryptoExchange.Net.Objects
|
||||
public class RequestDefinition
|
||||
{
|
||||
private string? _stringRep;
|
||||
private string? _fullUrl;
|
||||
|
||||
// Basics
|
||||
|
||||
/// <summary>
|
||||
/// Base address of the request
|
||||
/// </summary>
|
||||
public string BaseAddress { get; set; }
|
||||
/// <summary>
|
||||
/// Path of the request
|
||||
/// </summary>
|
||||
@@ -77,13 +82,31 @@ namespace CryptoExchange.Net.Objects
|
||||
/// </summary>
|
||||
public bool? ForcePathEndWithSlash { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Full url, host + path
|
||||
/// </summary>
|
||||
public string FullUrl
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_fullUrl != null)
|
||||
return _fullUrl;
|
||||
|
||||
var result = BaseAddress.AppendPath(Path);
|
||||
if (ForcePathEndWithSlash == true && !result.EndsWith("/"))
|
||||
result += "/";
|
||||
|
||||
_fullUrl = result;
|
||||
return _fullUrl;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ctor
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
/// <param name="method"></param>
|
||||
public RequestDefinition(string path, HttpMethod method)
|
||||
public RequestDefinition(string baseAddress, string path, HttpMethod method)
|
||||
{
|
||||
BaseAddress = baseAddress;
|
||||
Path = path;
|
||||
Method = method;
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using CryptoExchange.Net.RateLimiting.Interfaces;
|
||||
using System.Collections.Concurrent;
|
||||
using System.IO;
|
||||
using System.Net.Http;
|
||||
|
||||
namespace CryptoExchange.Net.Objects
|
||||
@@ -15,27 +16,30 @@ namespace CryptoExchange.Net.Objects
|
||||
/// Get a definition if it is already in the cache or create a new definition and add it to the cache
|
||||
/// </summary>
|
||||
/// <param name="method">The HttpMethod</param>
|
||||
/// <param name="baseAddress">The base address/host</param>
|
||||
/// <param name="path">Endpoint path</param>
|
||||
/// <param name="authenticated">Endpoint is authenticated</param>
|
||||
/// <returns></returns>
|
||||
public RequestDefinition GetOrCreate(HttpMethod method, string path, bool authenticated = false)
|
||||
=> GetOrCreate(method, path, null, 0, authenticated, null, null, null, null, null);
|
||||
public RequestDefinition GetOrCreate(HttpMethod method, string baseAddress, string path, bool authenticated = false)
|
||||
=> GetOrCreate(method, baseAddress, path, null, 0, authenticated, null, null, null, null, null, null, null);
|
||||
|
||||
/// <summary>
|
||||
/// Get a definition if it is already in the cache or create a new definition and add it to the cache
|
||||
/// </summary>
|
||||
/// <param name="method">The HttpMethod</param>
|
||||
/// <param name="baseAddress">The base address/host</param>
|
||||
/// <param name="path">Endpoint path</param>
|
||||
/// <param name="rateLimitGate">The rate limit gate</param>
|
||||
/// <param name="weight">Request weight</param>
|
||||
/// <param name="authenticated">Endpoint is authenticated</param>
|
||||
/// <returns></returns>
|
||||
public RequestDefinition GetOrCreate(HttpMethod method, string path, IRateLimitGate rateLimitGate, int weight = 1, bool authenticated = false)
|
||||
=> GetOrCreate(method, path, rateLimitGate, weight, authenticated, null, null, null, null, null);
|
||||
public RequestDefinition GetOrCreate(HttpMethod method, string baseAddress, string path, IRateLimitGate rateLimitGate, int weight = 1, bool authenticated = false)
|
||||
=> GetOrCreate(method, baseAddress, path, rateLimitGate, weight, authenticated, null, null, null, null, null, null, null);
|
||||
|
||||
/// <summary>
|
||||
/// Get a definition if it is already in the cache or create a new definition and add it to the cache
|
||||
/// </summary>
|
||||
/// <param name="baseAddress">The base address/host</param>
|
||||
/// <param name="method">The HttpMethod</param>
|
||||
/// <param name="path">Endpoint path</param>
|
||||
/// <param name="rateLimitGate">The rate limit gate</param>
|
||||
@@ -48,9 +52,11 @@ namespace CryptoExchange.Net.Objects
|
||||
/// <param name="preventCaching">Prevent request caching</param>
|
||||
/// <param name="tryParseOnNonSuccess">Try parse the response even when status is not success</param>
|
||||
/// <param name="forcePathEndWithSlash">Force trailing `/`</param>
|
||||
/// <param name="identifier">Optional request identifier override</param>
|
||||
/// <returns></returns>
|
||||
public RequestDefinition GetOrCreate(
|
||||
HttpMethod method,
|
||||
string baseAddress,
|
||||
string path,
|
||||
IRateLimitGate? rateLimitGate,
|
||||
int weight,
|
||||
@@ -61,45 +67,13 @@ namespace CryptoExchange.Net.Objects
|
||||
ArrayParametersSerialization? arraySerialization = null,
|
||||
bool? preventCaching = null,
|
||||
bool? tryParseOnNonSuccess = null,
|
||||
bool? forcePathEndWithSlash = null)
|
||||
=> GetOrCreate(method + path, method, path, rateLimitGate, weight, authenticated, limitGuard, requestBodyFormat, parameterPosition, arraySerialization, preventCaching, tryParseOnNonSuccess, forcePathEndWithSlash);
|
||||
|
||||
/// <summary>
|
||||
/// Get a definition if it is already in the cache or create a new definition and add it to the cache
|
||||
/// </summary>
|
||||
/// <param name="identifier">Request identifier</param>
|
||||
/// <param name="method">The HttpMethod</param>
|
||||
/// <param name="path">Endpoint path</param>
|
||||
/// <param name="rateLimitGate">The rate limit gate</param>
|
||||
/// <param name="limitGuard">The rate limit guard for this specific endpoint</param>
|
||||
/// <param name="weight">Request weight</param>
|
||||
/// <param name="authenticated">Endpoint is authenticated</param>
|
||||
/// <param name="requestBodyFormat">Request body format</param>
|
||||
/// <param name="parameterPosition">Parameter position</param>
|
||||
/// <param name="arraySerialization">Array serialization type</param>
|
||||
/// <param name="preventCaching">Prevent request caching</param>
|
||||
/// <param name="tryParseOnNonSuccess">Try parse the response even when status is not success</param>
|
||||
/// <param name="forcePathEndWithSlash">Force trailing `/`</param>
|
||||
/// <returns></returns>
|
||||
public RequestDefinition GetOrCreate(
|
||||
string identifier,
|
||||
HttpMethod method,
|
||||
string path,
|
||||
IRateLimitGate? rateLimitGate,
|
||||
int weight,
|
||||
bool authenticated,
|
||||
IRateLimitGuard? limitGuard = null,
|
||||
RequestBodyFormat? requestBodyFormat = null,
|
||||
HttpMethodParameterPosition? parameterPosition = null,
|
||||
ArrayParametersSerialization? arraySerialization = null,
|
||||
bool? preventCaching = null,
|
||||
bool? tryParseOnNonSuccess = null,
|
||||
bool? forcePathEndWithSlash = null)
|
||||
bool? forcePathEndWithSlash = null,
|
||||
string? identifier = null)
|
||||
{
|
||||
|
||||
if (!_definitions.TryGetValue(identifier, out var def))
|
||||
var identifierToUse = identifier ?? $"{path}{method.Method}{baseAddress}";
|
||||
if (!_definitions.TryGetValue(identifierToUse, out var def))
|
||||
{
|
||||
def = new RequestDefinition(path, method)
|
||||
def = new RequestDefinition(baseAddress, path, method)
|
||||
{
|
||||
Authenticated = authenticated,
|
||||
LimitGuard = limitGuard,
|
||||
@@ -110,9 +84,9 @@ namespace CryptoExchange.Net.Objects
|
||||
ParameterPosition = parameterPosition,
|
||||
PreventCaching = preventCaching ?? false,
|
||||
TryParseOnNonSuccess = tryParseOnNonSuccess ?? false,
|
||||
ForcePathEndWithSlash = forcePathEndWithSlash ?? false
|
||||
ForcePathEndWithSlash = forcePathEndWithSlash ?? false,
|
||||
};
|
||||
_definitions.TryAdd(identifier, def);
|
||||
_definitions.TryAdd(identifierToUse, def);
|
||||
}
|
||||
|
||||
return def;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using CryptoExchange.Net.Interfaces;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
|
||||
namespace CryptoExchange.Net.Objects
|
||||
@@ -12,29 +13,17 @@ namespace CryptoExchange.Net.Objects
|
||||
private string? _queryString;
|
||||
|
||||
/// <summary>
|
||||
/// Http method
|
||||
/// The request definition for the request
|
||||
/// </summary>
|
||||
public HttpMethod Method { get; set; }
|
||||
/// <summary>
|
||||
/// Whether the request needs authentication
|
||||
/// </summary>
|
||||
public bool Authenticated { get; set; }
|
||||
/// <summary>
|
||||
/// Base address for the request
|
||||
/// </summary>
|
||||
public string BaseAddress { get; set; }
|
||||
/// <summary>
|
||||
/// The request path
|
||||
/// </summary>
|
||||
public string Path { get; set; }
|
||||
public RequestDefinition RequestDefinition { get; set; }
|
||||
/// <summary>
|
||||
/// Query parameters
|
||||
/// </summary>
|
||||
public IDictionary<string, object>? QueryParameters { get; set; }
|
||||
public Parameters? QueryParameters { get; set; }
|
||||
/// <summary>
|
||||
/// Body parameters
|
||||
/// </summary>
|
||||
public IDictionary<string, object>? BodyParameters { get; set; }
|
||||
public Parameters? BodyParameters { get; set; }
|
||||
/// <summary>
|
||||
/// Request headers
|
||||
/// </summary>
|
||||
@@ -57,22 +46,16 @@ namespace CryptoExchange.Net.Objects
|
||||
/// </summary>
|
||||
public RestRequestConfiguration(
|
||||
RequestDefinition requestDefinition,
|
||||
string baseAddress,
|
||||
IDictionary<string, object>? queryParams,
|
||||
IDictionary<string, object>? bodyParams,
|
||||
Parameters? queryParams,
|
||||
Parameters? bodyParams,
|
||||
IDictionary<string, string>? headers,
|
||||
ArrayParametersSerialization arraySerialization,
|
||||
HttpMethodParameterPosition parametersPosition,
|
||||
RequestBodyFormat bodyFormat)
|
||||
{
|
||||
Method = requestDefinition.Method;
|
||||
Authenticated = requestDefinition.Authenticated;
|
||||
Path = requestDefinition.Path;
|
||||
BaseAddress = baseAddress;
|
||||
RequestDefinition = requestDefinition;
|
||||
QueryParameters = queryParams;
|
||||
BodyParameters = bodyParams;
|
||||
Headers = headers;
|
||||
ArraySerialization = arraySerialization;
|
||||
ParameterPosition = parametersPosition;
|
||||
BodyFormat = bodyFormat;
|
||||
}
|
||||
@@ -80,15 +63,15 @@ namespace CryptoExchange.Net.Objects
|
||||
/// <summary>
|
||||
/// Get the parameter collection based on the ParameterPosition
|
||||
/// </summary>
|
||||
public IDictionary<string, object> GetPositionParameters()
|
||||
public Parameters GetPositionParameters()
|
||||
{
|
||||
if (ParameterPosition == HttpMethodParameterPosition.InBody)
|
||||
{
|
||||
BodyParameters ??= new Dictionary<string, object>();
|
||||
BodyParameters ??= new Parameters(ParameterSerializationSettings.Default);
|
||||
return BodyParameters;
|
||||
}
|
||||
|
||||
QueryParameters ??= new Dictionary<string, object>();
|
||||
QueryParameters ??= new Parameters(ParameterSerializationSettings.Default);
|
||||
return QueryParameters;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Text;
|
||||
|
||||
namespace CryptoExchange.Net.Objects;
|
||||
|
||||
/// <summary>
|
||||
/// Call result
|
||||
/// </summary>
|
||||
public record CallResult : ICallResult
|
||||
{
|
||||
private static CallResult _successResult = new CallResult();
|
||||
|
||||
/// <inheritdoc />
|
||||
public Error? Error { get; init; }
|
||||
/// <inheritdoc />
|
||||
[MemberNotNullWhen(false, nameof(Error))]
|
||||
public bool Success => Error == null;
|
||||
|
||||
/// <summary>
|
||||
/// Create an error response
|
||||
/// </summary>
|
||||
/// <param name="error">The error</param>
|
||||
public static CallResult Fail(Error error) => new CallResult { Error = error };
|
||||
/// <summary>
|
||||
/// Create a success result
|
||||
/// </summary>
|
||||
public static CallResult Ok() => _successResult;
|
||||
/// <summary>
|
||||
/// Create a success result
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Result type</typeparam>
|
||||
/// <param name="originalData">The original string data</param>
|
||||
/// <param name="data">Data type</param>
|
||||
public static CallResult<T> Ok<T>(T data, string? originalData = null) => new CallResult<T> { Data = data, OriginalData = originalData };
|
||||
/// <summary>
|
||||
/// Create an error response
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Result type</typeparam>
|
||||
/// <param name="originalData">The original string data</param>
|
||||
/// <param name="error">The error</param>
|
||||
public static CallResult<T> Fail<T>(Error error, string? originalData = null) => new CallResult<T> { Error = error, OriginalData = originalData };
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
return Success ? $"Success" : $"Error: {Error}";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public record CallResult<T> : CallResult, ICallResult<T>
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public new Error? Error
|
||||
{
|
||||
get => base.Error;
|
||||
init => base.Error = value;
|
||||
}
|
||||
/// <inheritdoc />
|
||||
[MemberNotNullWhen(false, nameof(Error))]
|
||||
[MemberNotNullWhen(true, nameof(Data))]
|
||||
public new bool Success => Error == null;
|
||||
|
||||
/// <summary>
|
||||
/// The data returned by the call, only available when Success = true
|
||||
/// </summary>
|
||||
public T? Data { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The original data returned by the call, only available when `OutputOriginalData` is set to `true` in the client options
|
||||
/// </summary>
|
||||
public string? OriginalData { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Create an error response
|
||||
/// </summary>
|
||||
/// <param name="error">The error</param>
|
||||
/// <param name="originalData">The original string data</param>
|
||||
public static CallResult<T> Fail(Error error, string? originalData = null) => new CallResult<T> { Error = error, OriginalData = originalData };
|
||||
/// <summary>
|
||||
/// Create a success result
|
||||
/// </summary>
|
||||
/// <param name="data">The data</param>
|
||||
/// <param name="originalData">The original string data</param>
|
||||
/// <returns></returns>
|
||||
public static CallResult<T> Ok(T data, string? originalData = null) => new CallResult<T> { Data = data, OriginalData = originalData };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Call result for an exchange
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Data type</typeparam>
|
||||
public record ExchangeCallResult<T> : CallResult<T>
|
||||
{
|
||||
/// <summary>
|
||||
/// Exchange name
|
||||
/// </summary>
|
||||
public string Exchange { get; set; } = string.Empty;
|
||||
/// <summary>
|
||||
/// Create an error response
|
||||
/// </summary>
|
||||
/// <param name="exchange">The exchange name</param>
|
||||
/// <param name="error">The error</param>
|
||||
/// <param name="originalData">The original string data</param>
|
||||
public static ExchangeCallResult<T> Fail(string exchange, Error error, string? originalData = null) => new ExchangeCallResult<T> { Exchange = exchange, Error = error };
|
||||
/// <summary>
|
||||
/// Create a success result
|
||||
/// </summary>
|
||||
/// <param name="exchange">The exchange name</param>
|
||||
/// <param name="data">The data</param>
|
||||
/// <param name="originalData">The original string data</param>
|
||||
/// <returns></returns>
|
||||
public static ExchangeCallResult<T> Ok(string exchange, T data, string? originalData = null) => new ExchangeCallResult<T> { Exchange = exchange, Data = data };
|
||||
}
|
||||
@@ -0,0 +1,286 @@
|
||||
using CryptoExchange.Net.SharedApis;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text;
|
||||
|
||||
namespace CryptoExchange.Net.Objects;
|
||||
|
||||
/// <summary>
|
||||
/// HTTP call result
|
||||
/// </summary>
|
||||
public record HttpResult : IHttpResult
|
||||
{
|
||||
/// <summary>
|
||||
/// Create a new success HTTP result
|
||||
/// </summary>
|
||||
public static HttpResult<T> Ok<T>(
|
||||
string exchange,
|
||||
HttpStatusCode code,
|
||||
Version version,
|
||||
HttpResponseHeaders responseHeaders,
|
||||
TimeSpan elapsed,
|
||||
long? contentLength,
|
||||
string? originalData,
|
||||
int requestId,
|
||||
string uri,
|
||||
string? content,
|
||||
HttpMethod method,
|
||||
HttpRequestHeaders requestHeaders,
|
||||
ResultDataSource source,
|
||||
T data) =>
|
||||
new HttpResult<T>(exchange, data, null)
|
||||
{
|
||||
ResponseStatusCode = code,
|
||||
HttpVersion = version,
|
||||
ResponseHeaders = responseHeaders,
|
||||
ResponseTime = elapsed,
|
||||
ResponseLength = contentLength,
|
||||
OriginalData = originalData,
|
||||
RequestId = requestId,
|
||||
RequestUrl = uri,
|
||||
RequestBody = content,
|
||||
RequestMethod = method,
|
||||
RequestHeaders = requestHeaders,
|
||||
DataSource = source,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Create a new success HTTP result
|
||||
/// </summary>
|
||||
public static HttpResult<T> Ok<T>(IHttpResult result, T data, PageRequest? pageRequest = null) =>
|
||||
new HttpResult<T>(result.Exchange, data, null)
|
||||
{
|
||||
ResponseStatusCode = result.ResponseStatusCode,
|
||||
HttpVersion = result.HttpVersion,
|
||||
ResponseHeaders = result.ResponseHeaders,
|
||||
ResponseTime = result.ResponseTime,
|
||||
ResponseLength = result.ResponseLength,
|
||||
OriginalData = result.OriginalData,
|
||||
RequestId = result.RequestId,
|
||||
RequestUrl = result.RequestUrl,
|
||||
RequestBody = result.RequestBody,
|
||||
RequestMethod = result.RequestMethod,
|
||||
RequestHeaders = result.RequestHeaders,
|
||||
DataSource = result.DataSource,
|
||||
Error = result.Error,
|
||||
Data = data,
|
||||
NextPageRequest = pageRequest
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Create a new error HTTP result
|
||||
/// </summary>
|
||||
public static HttpResult<T> Fail<T>(string exchange, Error error) => new HttpResult<T>(exchange, default, error);
|
||||
|
||||
/// <summary>
|
||||
/// Create a new error HTTP result
|
||||
/// </summary>
|
||||
public static HttpResult<T> Fail<T>(IHttpResult result, Error? error = null, T? data = default)
|
||||
=> new HttpResult<T>(result.Exchange, data, error ?? result.Error)
|
||||
{
|
||||
ResponseStatusCode = result.ResponseStatusCode,
|
||||
HttpVersion = result.HttpVersion,
|
||||
ResponseHeaders = result.ResponseHeaders,
|
||||
ResponseTime = result.ResponseTime,
|
||||
ResponseLength = result.ResponseLength,
|
||||
OriginalData = result.OriginalData,
|
||||
RequestId = result.RequestId,
|
||||
RequestUrl = result.RequestUrl,
|
||||
RequestBody = result.RequestBody,
|
||||
RequestMethod = result.RequestMethod,
|
||||
RequestHeaders = result.RequestHeaders,
|
||||
DataSource = result.DataSource,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Create a new error HTTP result
|
||||
/// </summary>
|
||||
public static HttpResult<T> Fail<T>(
|
||||
string exchange,
|
||||
HttpStatusCode? code,
|
||||
Version? version,
|
||||
HttpResponseHeaders? responseHeaders,
|
||||
TimeSpan elapsed,
|
||||
long? contentLength,
|
||||
string? originalData,
|
||||
int requestId,
|
||||
string uri,
|
||||
string? content,
|
||||
HttpMethod method,
|
||||
HttpRequestHeaders requestHeaders,
|
||||
ResultDataSource source,
|
||||
Error error,
|
||||
T? result = default) =>
|
||||
new HttpResult<T>(exchange, result, error)
|
||||
{
|
||||
ResponseStatusCode = code,
|
||||
HttpVersion = version,
|
||||
ResponseHeaders = responseHeaders,
|
||||
ResponseTime = elapsed,
|
||||
ResponseLength = contentLength,
|
||||
OriginalData = originalData,
|
||||
RequestId = requestId,
|
||||
RequestUrl = uri,
|
||||
RequestBody = content,
|
||||
RequestMethod = method,
|
||||
RequestHeaders = requestHeaders,
|
||||
DataSource = source,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Create a new error HTTP result
|
||||
/// </summary>
|
||||
public static HttpResult Fail(string exchange, Error error) => new HttpResult() { Exchange = exchange, Error = error };
|
||||
|
||||
/// <summary>
|
||||
/// Create a new error HTTP result
|
||||
/// </summary>
|
||||
public static HttpResult Fail(IHttpResult result, Error? error = null)
|
||||
=> new HttpResult()
|
||||
{
|
||||
ResponseStatusCode = result.ResponseStatusCode,
|
||||
HttpVersion = result.HttpVersion,
|
||||
ResponseHeaders = result.ResponseHeaders,
|
||||
ResponseTime = result.ResponseTime,
|
||||
ResponseLength = result.ResponseLength,
|
||||
OriginalData = result.OriginalData,
|
||||
RequestId = result.RequestId,
|
||||
RequestUrl = result.RequestUrl,
|
||||
RequestBody = result.RequestBody,
|
||||
RequestMethod = result.RequestMethod,
|
||||
RequestHeaders = result.RequestHeaders,
|
||||
DataSource = result.DataSource,
|
||||
Exchange = result.Exchange,
|
||||
Error = error ?? result.Error
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Create a new success HTTP result
|
||||
/// </summary>
|
||||
public static HttpResult Ok(IHttpResult result)
|
||||
=> new HttpResult()
|
||||
{
|
||||
ResponseStatusCode = result.ResponseStatusCode,
|
||||
HttpVersion = result.HttpVersion,
|
||||
ResponseHeaders = result.ResponseHeaders,
|
||||
ResponseTime = result.ResponseTime,
|
||||
ResponseLength = result.ResponseLength,
|
||||
OriginalData = result.OriginalData,
|
||||
RequestId = result.RequestId,
|
||||
RequestUrl = result.RequestUrl,
|
||||
RequestBody = result.RequestBody,
|
||||
RequestMethod = result.RequestMethod,
|
||||
RequestHeaders = result.RequestHeaders,
|
||||
DataSource = result.DataSource,
|
||||
Exchange = result.Exchange,
|
||||
};
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Exchange name
|
||||
/// </summary>
|
||||
public string Exchange { get; init; } = string.Empty;
|
||||
|
||||
/// <inheritdoc />
|
||||
public Error? Error { get; internal set; }
|
||||
/// <inheritdoc />
|
||||
[MemberNotNullWhen(false, nameof(Error))]
|
||||
public bool Success => Error == null;
|
||||
/// <summary>
|
||||
/// The original data returned by the call, only available when `OutputOriginalData` is set to `true` in the client options
|
||||
/// </summary>
|
||||
public string? OriginalData { get; init; }
|
||||
/// <summary>
|
||||
/// The request http method
|
||||
/// </summary>
|
||||
public HttpMethod? RequestMethod { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// HTTP protocol version
|
||||
/// </summary>
|
||||
public Version? HttpVersion { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The headers sent with the request
|
||||
/// </summary>
|
||||
public HttpRequestHeaders? RequestHeaders { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The request id
|
||||
/// </summary>
|
||||
public int? RequestId { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The url which was requested
|
||||
/// </summary>
|
||||
public string? RequestUrl { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The body of the request
|
||||
/// </summary>
|
||||
public string? RequestBody { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Length in bytes of the response
|
||||
/// </summary>
|
||||
public long? ResponseLength { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The status code of the response. Note that a OK status does not always indicate success, check the Success parameter for this.
|
||||
/// </summary>
|
||||
public HttpStatusCode? ResponseStatusCode { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The response headers
|
||||
/// </summary>
|
||||
public HttpResponseHeaders? ResponseHeaders { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The time between sending the request and receiving the response
|
||||
/// </summary>
|
||||
public TimeSpan? ResponseTime { get; init; }
|
||||
/// <summary>
|
||||
/// The data source of this result
|
||||
/// </summary>
|
||||
public ResultDataSource DataSource { get; init; } = ResultDataSource.Server;
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public record HttpResult<T> : HttpResult, IHttpResult<T>
|
||||
{
|
||||
/// <summary>
|
||||
/// ctor
|
||||
/// </summary>
|
||||
public HttpResult(string exchange, T? value, Error? error)
|
||||
{
|
||||
Exchange = exchange;
|
||||
Data = value;
|
||||
Error = error;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public new Error? Error
|
||||
{
|
||||
get => base.Error;
|
||||
internal set => base.Error = value;
|
||||
}
|
||||
/// <inheritdoc />
|
||||
[MemberNotNullWhen(false, nameof(Error))]
|
||||
[MemberNotNullWhen(true, nameof(Data))]
|
||||
public new bool Success => Error == null;
|
||||
|
||||
/// <summary>
|
||||
/// The data returned by the call, only available when Success = true
|
||||
/// </summary>
|
||||
public T? Data { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Next page request, only potentially available when using Shared API's
|
||||
/// </summary>
|
||||
public PageRequest? NextPageRequest { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Text;
|
||||
|
||||
namespace CryptoExchange.Net.Objects;
|
||||
|
||||
/// <summary>
|
||||
/// Call result
|
||||
/// </summary>
|
||||
public interface ICallResult
|
||||
{
|
||||
/// <summary>
|
||||
/// An error if the call didn't succeed, will always be filled if Success = false
|
||||
/// </summary>
|
||||
Error? Error { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether the call was successful
|
||||
/// </summary>
|
||||
[MemberNotNullWhen(false, nameof(Error))]
|
||||
bool Success { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Call result
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Result data type</typeparam>
|
||||
public interface ICallResult<T> : ICallResult
|
||||
{
|
||||
/// <inheritdoc />
|
||||
new Error? Error { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
[MemberNotNullWhen(false, nameof(Error))]
|
||||
[MemberNotNullWhen(true, nameof(Data))]
|
||||
new bool Success { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The result data, only available when Success = true
|
||||
/// </summary>
|
||||
T? Data { get; }
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text;
|
||||
|
||||
namespace CryptoExchange.Net.Objects
|
||||
{
|
||||
/// <summary>
|
||||
/// HTTP call result
|
||||
/// </summary>
|
||||
public interface IHttpResult : ICallResult
|
||||
{
|
||||
/// <summary>
|
||||
/// Exchange name
|
||||
/// </summary>
|
||||
string Exchange { get; init; }
|
||||
/// <summary>
|
||||
/// The original data returned by the call, only available when `OutputOriginalData` is set to `true` in the client options
|
||||
/// </summary>
|
||||
string? OriginalData { get; init; }
|
||||
/// <summary>
|
||||
/// The request http method
|
||||
/// </summary>
|
||||
HttpMethod? RequestMethod { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// HTTP protocol version
|
||||
/// </summary>
|
||||
Version? HttpVersion { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The headers sent with the request
|
||||
/// </summary>
|
||||
HttpRequestHeaders? RequestHeaders { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The request id
|
||||
/// </summary>
|
||||
int? RequestId { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The url which was requested
|
||||
/// </summary>
|
||||
string? RequestUrl { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The body of the request
|
||||
/// </summary>
|
||||
string? RequestBody { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Length in bytes of the response
|
||||
/// </summary>
|
||||
long? ResponseLength { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The status code of the response. Note that a OK status does not always indicate success, check the Success parameter for this.
|
||||
/// </summary>
|
||||
HttpStatusCode? ResponseStatusCode { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The response headers
|
||||
/// </summary>
|
||||
HttpResponseHeaders? ResponseHeaders { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The time between sending the request and receiving the response
|
||||
/// </summary>
|
||||
TimeSpan? ResponseTime { get; init; }
|
||||
/// <summary>
|
||||
/// The data source of this result
|
||||
/// </summary>
|
||||
ResultDataSource DataSource { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// HTTP call result
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Result data type</typeparam>
|
||||
public interface IHttpResult<T> : IHttpResult, ICallResult<T>
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text;
|
||||
|
||||
namespace CryptoExchange.Net.Objects
|
||||
{
|
||||
/// <summary>
|
||||
/// WebSocket call result
|
||||
/// </summary>
|
||||
public interface IWebSocketResult : ICallResult
|
||||
{
|
||||
/// <summary>
|
||||
/// Exchange name
|
||||
/// </summary>
|
||||
string Exchange { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The request id
|
||||
/// </summary>
|
||||
public int? RequestId { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The url which was requested
|
||||
/// </summary>
|
||||
public int? ConnectionId { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The websocket url
|
||||
/// </summary>
|
||||
public string? Url { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The time between sending the request and receiving the response
|
||||
/// </summary>
|
||||
public TimeSpan? ResponseTime { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// WebSocket call result
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Data result type</typeparam>
|
||||
public interface IWebSocketResult<T> : IWebSocketResult, ICallResult<T>
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Query result
|
||||
/// </summary>
|
||||
public interface IQueryResult : IWebSocketResult
|
||||
{
|
||||
/// <summary>
|
||||
/// The original returned data, only available when OutputOriginalData is set to true in the client options
|
||||
/// </summary>
|
||||
public string? OriginalData { get; init; }
|
||||
/// <summary>
|
||||
/// The query request body
|
||||
/// </summary>
|
||||
public string? RequestBody { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Query result
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public interface IQueryResult<T> : IQueryResult, IWebSocketResult<T>
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace CryptoExchange.Net.Objects;
|
||||
|
||||
/// <summary>
|
||||
/// Void result
|
||||
/// </summary>
|
||||
public readonly struct Unit
|
||||
{
|
||||
/// <summary>
|
||||
/// Void value
|
||||
/// </summary>
|
||||
public static readonly Unit Value = default;
|
||||
/// <summary>
|
||||
/// Type
|
||||
/// </summary>
|
||||
public static Type Type { get; } = typeof(Unit);
|
||||
}
|
||||
@@ -0,0 +1,320 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Text;
|
||||
|
||||
namespace CryptoExchange.Net.Objects;
|
||||
|
||||
/// <summary>
|
||||
/// WebSocket call result
|
||||
/// </summary>
|
||||
public record WebSocketResult : IWebSocketResult
|
||||
{
|
||||
/// <summary>
|
||||
/// ctor
|
||||
/// </summary>
|
||||
public WebSocketResult(string exchange, Error? error)
|
||||
{
|
||||
Exchange = exchange;
|
||||
Error = error;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new success WebSocket result
|
||||
/// </summary>
|
||||
public static WebSocketResult<T> Ok<T>(IWebSocketResult result, T data) =>
|
||||
new WebSocketResult<T>(result.Exchange, data, null)
|
||||
{
|
||||
ConnectionId = result.ConnectionId,
|
||||
Url = result.Url,
|
||||
RequestId = result.RequestId,
|
||||
ResponseTime = result.ResponseTime,
|
||||
Error = result.Error,
|
||||
Data = data
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Create a new success WebSocket result
|
||||
/// </summary>
|
||||
public static WebSocketResult<T> Ok<T>(
|
||||
string exchange,
|
||||
int connectionId,
|
||||
TimeSpan elapsed,
|
||||
int requestId,
|
||||
string? url,
|
||||
T data) =>
|
||||
new WebSocketResult<T>(exchange, data, null)
|
||||
{
|
||||
ResponseTime = elapsed,
|
||||
RequestId = requestId,
|
||||
ConnectionId = connectionId,
|
||||
Url = url
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Create a new success WebSocket result
|
||||
/// </summary>
|
||||
public static WebSocketResult Ok(
|
||||
string exchange,
|
||||
int connectionId,
|
||||
TimeSpan elapsed,
|
||||
int requestId,
|
||||
string? url) =>
|
||||
new WebSocketResult(exchange, null)
|
||||
{
|
||||
ResponseTime = elapsed,
|
||||
RequestId = requestId,
|
||||
ConnectionId = connectionId,
|
||||
Url = url
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Create a new error WebSocket result
|
||||
/// </summary>
|
||||
public static WebSocketResult Fail(string exchange, Error error) => new WebSocketResult(exchange, error);
|
||||
/// <summary>
|
||||
/// Create a new error WebSocket result
|
||||
/// </summary>
|
||||
public static WebSocketResult Fail(
|
||||
string exchange,
|
||||
int connectionId,
|
||||
TimeSpan elapsed,
|
||||
int requestId,
|
||||
string? url,
|
||||
Error error) =>
|
||||
new WebSocketResult(exchange, error)
|
||||
{
|
||||
ResponseTime = elapsed,
|
||||
RequestId = requestId,
|
||||
ConnectionId = connectionId,
|
||||
Url = url
|
||||
};
|
||||
/// <summary>
|
||||
/// Create a new error WebSocket result
|
||||
/// </summary>
|
||||
public static WebSocketResult<T> Fail<T>(IWebSocketResult result, Error? error = null, T? data = default)
|
||||
=> new WebSocketResult<T>(result.Exchange, data, error ?? result.Error)
|
||||
{
|
||||
ConnectionId = result.ConnectionId,
|
||||
Url = result.Url,
|
||||
RequestId = result.RequestId,
|
||||
ResponseTime = result.ResponseTime,
|
||||
};
|
||||
/// <summary>
|
||||
/// Create a new error WebSocket result
|
||||
/// </summary>
|
||||
public static WebSocketResult<T> Fail<T>(string exchange, Error error) => new WebSocketResult<T>(exchange, default, error);
|
||||
|
||||
/// <summary>
|
||||
/// Create a new error WebSocket result
|
||||
/// </summary>
|
||||
public static WebSocketResult<T> Fail<T>(
|
||||
string exchange,
|
||||
int connectionId,
|
||||
TimeSpan elapsed,
|
||||
int requestId,
|
||||
string? url,
|
||||
Error error) =>
|
||||
new WebSocketResult<T>(exchange, default, error)
|
||||
{
|
||||
ResponseTime = elapsed,
|
||||
RequestId = requestId,
|
||||
ConnectionId = connectionId,
|
||||
Url = url
|
||||
};
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Exchange name
|
||||
/// </summary>
|
||||
public string Exchange { get; init; }
|
||||
/// <inheritdoc />
|
||||
public Error? Error { get; init; }
|
||||
/// <inheritdoc />
|
||||
[MemberNotNullWhen(false, nameof(Error))]
|
||||
public bool Success => Error == null;
|
||||
|
||||
/// <summary>
|
||||
/// The request id
|
||||
/// </summary>
|
||||
public int? RequestId { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The url which was requested
|
||||
/// </summary>
|
||||
public int? ConnectionId { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The websocket url
|
||||
/// </summary>
|
||||
public string? Url { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The time between sending the request and receiving the response
|
||||
/// </summary>
|
||||
public TimeSpan? ResponseTime { get; init; }
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public record WebSocketResult<T> : WebSocketResult, IWebSocketResult<T>
|
||||
{
|
||||
/// <summary>
|
||||
/// ctor
|
||||
/// </summary>
|
||||
public WebSocketResult(string exchange, T? value, Error? error): base(exchange, error)
|
||||
{
|
||||
Data = value;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public new Error? Error
|
||||
{
|
||||
get => base.Error;
|
||||
init => base.Error = value;
|
||||
}
|
||||
/// <inheritdoc />
|
||||
[MemberNotNullWhen(false, nameof(Error))]
|
||||
[MemberNotNullWhen(true, nameof(Data))]
|
||||
public new bool Success => Error == null;
|
||||
/// <summary>
|
||||
/// The data returned by the call, only available when Success = true
|
||||
/// </summary>
|
||||
public T? Data { get; init; }
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public record QueryResult : WebSocketResult
|
||||
{
|
||||
/// <summary>
|
||||
/// ctor
|
||||
/// </summary>
|
||||
public QueryResult(string exchange, Error? error) : base(exchange, error)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new error Query result
|
||||
/// </summary>
|
||||
public new static QueryResult Fail(string exchange, Error error) => new QueryResult(exchange, error);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Create a new error WebSocket result
|
||||
/// </summary>
|
||||
public static QueryResult Fail(IQueryResult result, Error? error = null)
|
||||
=> new QueryResult(result.Exchange, error ?? result.Error)
|
||||
{
|
||||
ConnectionId = result.ConnectionId,
|
||||
Url = result.Url,
|
||||
RequestId = result.RequestId,
|
||||
ResponseTime = result.ResponseTime,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Create a new success query result
|
||||
/// </summary>
|
||||
public static QueryResult<T> Ok<T>(
|
||||
string exchange,
|
||||
int connectionId,
|
||||
TimeSpan elapsed,
|
||||
int requestId,
|
||||
string? requestBody,
|
||||
string? url,
|
||||
string? originalData,
|
||||
T data) =>
|
||||
new QueryResult<T>(exchange, data, null)
|
||||
{
|
||||
ResponseTime = elapsed,
|
||||
RequestId = requestId,
|
||||
RequestBody = requestBody,
|
||||
ConnectionId = connectionId,
|
||||
Url = url,
|
||||
OriginalData = originalData,
|
||||
};
|
||||
/// <summary>
|
||||
/// Create a new success WebSocket result
|
||||
/// </summary>
|
||||
public static QueryResult<T> Ok<T>(IQueryResult result, T data) =>
|
||||
new QueryResult<T>(result.Exchange, data, null)
|
||||
{
|
||||
ConnectionId = result.ConnectionId,
|
||||
Url = result.Url,
|
||||
RequestId = result.RequestId,
|
||||
RequestBody = result.RequestBody,
|
||||
ResponseTime = result.ResponseTime,
|
||||
Error = result.Error,
|
||||
OriginalData = result.OriginalData,
|
||||
Data = data
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Create a new error WebSocket result
|
||||
/// </summary>
|
||||
public static QueryResult<T> Fail<T>(
|
||||
string exchange,
|
||||
int connectionId,
|
||||
TimeSpan elapsed,
|
||||
int requestId,
|
||||
string? requestBody,
|
||||
string? url,
|
||||
string? originalData,
|
||||
Error error) =>
|
||||
new QueryResult<T>(exchange, default, error)
|
||||
{
|
||||
ResponseTime = elapsed,
|
||||
RequestId = requestId,
|
||||
RequestBody = requestBody,
|
||||
ConnectionId = connectionId,
|
||||
OriginalData = originalData,
|
||||
Url = url
|
||||
};
|
||||
/// <summary>
|
||||
/// Create a new error WebSocket result
|
||||
/// </summary>
|
||||
public static QueryResult<T> Fail<T>(IQueryResult result, Error? error = null, T? data = default)
|
||||
=> new QueryResult<T>(result.Exchange, data, error ?? result.Error)
|
||||
{
|
||||
ConnectionId = result.ConnectionId,
|
||||
Url = result.Url,
|
||||
RequestId = result.RequestId,
|
||||
RequestBody = result.RequestBody,
|
||||
OriginalData = result.OriginalData,
|
||||
ResponseTime = result.ResponseTime,
|
||||
};
|
||||
/// <summary>
|
||||
/// Create a new error WebSocket result
|
||||
/// </summary>
|
||||
public new static QueryResult<T> Fail<T>(string exchange, Error error) => new QueryResult<T>(exchange, default, error);
|
||||
|
||||
/// <inheritdoc />
|
||||
public string? RequestBody { get; init; }
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public record QueryResult<T> : QueryResult, IQueryResult<T>
|
||||
{
|
||||
/// <summary>
|
||||
/// ctor
|
||||
/// </summary>
|
||||
public QueryResult(string exchange, T? value, Error? error) : base(exchange, error)
|
||||
{
|
||||
Data = value;
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public new Error? Error
|
||||
{
|
||||
get => base.Error;
|
||||
init => base.Error = value;
|
||||
}
|
||||
/// <inheritdoc />
|
||||
[MemberNotNullWhen(false, nameof(Error))]
|
||||
[MemberNotNullWhen(true, nameof(Data))]
|
||||
public new bool Success => Error == null;
|
||||
/// <inheritdoc />
|
||||
public T? Data { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public string? OriginalData { get; init; }
|
||||
}
|
||||
Reference in New Issue
Block a user