1
0
mirror of https://github.com/JKorf/CryptoExchange.Net synced 2025-06-08 00:16:27 +00:00

Added Request info and ResponseTime to WebCallResult, refactored CallResult ctors

This commit is contained in:
Jkorf 2022-01-14 16:47:49 +01:00
parent c6bf0d67a4
commit 8f6e853e13
9 changed files with 155 additions and 138 deletions

View File

@ -93,28 +93,28 @@ namespace CryptoExchange.Net
{
var info = "Empty data object received";
log.Write(LogLevel.Error, info);
return new CallResult<JToken>(null, new DeserializeError(info, data));
return new CallResult<JToken>(new DeserializeError(info, data));
}
try
{
return new CallResult<JToken>(JToken.Parse(data), null);
return new CallResult<JToken>(JToken.Parse(data));
}
catch (JsonReaderException jre)
{
var info = $"Deserialize JsonReaderException: {jre.Message}, Path: {jre.Path}, LineNumber: {jre.LineNumber}, LinePosition: {jre.LinePosition}";
return new CallResult<JToken>(null, new DeserializeError(info, data));
return new CallResult<JToken>(new DeserializeError(info, data));
}
catch (JsonSerializationException jse)
{
var info = $"Deserialize JsonSerializationException: {jse.Message}";
return new CallResult<JToken>(null, new DeserializeError(info, data));
return new CallResult<JToken>(new DeserializeError(info, data));
}
catch (Exception ex)
{
var exceptionInfo = ex.ToLogString();
var info = $"Deserialize Unknown Exception: {exceptionInfo}";
return new CallResult<JToken>(null, new DeserializeError(info, data));
return new CallResult<JToken>(new DeserializeError(info, data));
}
}
@ -132,7 +132,7 @@ namespace CryptoExchange.Net
if (!tokenResult)
{
log.Write(LogLevel.Error, tokenResult.Error!.Message);
return new CallResult<T>(default, tokenResult.Error);
return new CallResult<T>( tokenResult.Error);
}
return Deserialize<T>(tokenResult.Data, serializer, requestId);
@ -152,26 +152,26 @@ namespace CryptoExchange.Net
try
{
return new CallResult<T>(obj.ToObject<T>(serializer), null);
return new CallResult<T>(obj.ToObject<T>(serializer)!);
}
catch (JsonReaderException jre)
{
var info = $"{(requestId != null ? $"[{requestId}] " : "")}Deserialize JsonReaderException: {jre.Message} Path: {jre.Path}, LineNumber: {jre.LineNumber}, LinePosition: {jre.LinePosition}, data: {obj}";
log.Write(LogLevel.Error, info);
return new CallResult<T>(default, new DeserializeError(info, obj));
return new CallResult<T>(new DeserializeError(info, obj));
}
catch (JsonSerializationException jse)
{
var info = $"{(requestId != null ? $"[{requestId}] " : "")}Deserialize JsonSerializationException: {jse.Message} data: {obj}";
log.Write(LogLevel.Error, info);
return new CallResult<T>(default, new DeserializeError(info, obj));
return new CallResult<T>(new DeserializeError(info, obj));
}
catch (Exception ex)
{
var exceptionInfo = ex.ToLogString();
var info = $"{(requestId != null ? $"[{requestId}] " : "")}Deserialize Unknown Exception: {exceptionInfo}, data: {obj}";
log.Write(LogLevel.Error, info);
return new CallResult<T>(default, new DeserializeError(info, obj));
return new CallResult<T>(new DeserializeError(info, obj));
}
}
@ -208,7 +208,7 @@ namespace CryptoExchange.Net
// If we don't have to keep track of the original json data we can use the JsonTextReader to deserialize the stream directly
// into the desired object, which has increased performance over first reading the string value into memory and deserializing from that
using var jsonReader = new JsonTextReader(reader);
return new CallResult<T>(serializer.Deserialize<T>(jsonReader), null);
return new CallResult<T>(serializer.Deserialize<T>(jsonReader)!);
}
catch (JsonReaderException jre)
{
@ -222,7 +222,7 @@ namespace CryptoExchange.Net
else
data = "[Data only available in Debug LogLevel]";
log.Write(LogLevel.Error, $"{(requestId != null ? $"[{requestId}] " : "")}Deserialize JsonReaderException: {jre.Message}, Path: {jre.Path}, LineNumber: {jre.LineNumber}, LinePosition: {jre.LinePosition}, data: {data}");
return new CallResult<T>(default, new DeserializeError($"Deserialize JsonReaderException: {jre.Message}, Path: {jre.Path}, LineNumber: {jre.LineNumber}, LinePosition: {jre.LinePosition}", data));
return new CallResult<T>(new DeserializeError($"Deserialize JsonReaderException: {jre.Message}, Path: {jre.Path}, LineNumber: {jre.LineNumber}, LinePosition: {jre.LinePosition}", data));
}
catch (JsonSerializationException jse)
{
@ -236,7 +236,7 @@ namespace CryptoExchange.Net
data = "[Data only available in Debug LogLevel]";
log.Write(LogLevel.Error, $"{(requestId != null ? $"[{requestId}] " : "")}Deserialize JsonSerializationException: {jse.Message}, data: {data}");
return new CallResult<T>(default, new DeserializeError($"Deserialize JsonSerializationException: {jse.Message}", data));
return new CallResult<T>(new DeserializeError($"Deserialize JsonSerializationException: {jse.Message}", data));
}
catch (Exception ex)
{
@ -250,7 +250,7 @@ namespace CryptoExchange.Net
var exceptionInfo = ex.ToLogString();
log.Write(LogLevel.Error, $"{(requestId != null ? $"[{requestId}] " : "")}Deserialize Unknown Exception: {exceptionInfo}, data: {data}");
return new CallResult<T>(default, new DeserializeError($"Deserialize Unknown Exception: {exceptionInfo}", data));
return new CallResult<T>(new DeserializeError($"Deserialize Unknown Exception: {exceptionInfo}", data));
}
}

View File

@ -136,7 +136,7 @@ namespace CryptoExchange.Net
if (signed && apiClient.AuthenticationProvider == null)
{
log.Write(LogLevel.Warning, $"[{requestId}] Request {uri.AbsolutePath} failed because no ApiCredentials were provided");
return new WebCallResult<T>(null, null, null, new NoApiCredentialsError());
return new WebCallResult<T>(new NoApiCredentialsError());
}
var paramsPosition = parameterPosition ?? ParameterPositions[method];
@ -145,7 +145,7 @@ namespace CryptoExchange.Net
{
var limitResult = await limiter.LimitRequestAsync(log, uri.AbsolutePath, method, signed, apiClient.Options.ApiCredentials?.Key, apiClient.Options.RateLimitingBehaviour, requestWeight, cancellationToken).ConfigureAwait(false);
if (!limitResult.Success)
return new WebCallResult<T>(null, null, null, limitResult.Error);
return new WebCallResult<T>(limitResult.Error!);
}
string? paramString = "";
@ -196,16 +196,16 @@ namespace CryptoExchange.Net
// Validate if it is valid json. Sometimes other data will be returned, 502 error html pages for example
var parseResult = ValidateJson(data);
if (!parseResult.Success)
return WebCallResult<T>.CreateErrorResult(response.StatusCode, response.ResponseHeaders, parseResult.Error!);
return new WebCallResult<T>(response.StatusCode, response.ResponseHeaders, ClientOptions.OutputOriginalData ? data : null, request.Uri.ToString(), request.Content, request.Method, request.GetHeaders(), default, parseResult.Error!);
// Let the library implementation see if it is an error response, and if so parse the error
var error = await TryParseErrorAsync(parseResult.Data).ConfigureAwait(false);
if (error != null)
return WebCallResult<T>.CreateErrorResult(response.StatusCode, response.ResponseHeaders, error);
return new WebCallResult<T>(response.StatusCode, response.ResponseHeaders, ClientOptions.OutputOriginalData ? data : null, request.Uri.ToString(), request.Content, request.Method, request.GetHeaders(), default, error!);
// Not an error, so continue deserializing
var deserializeResult = Deserialize<T>(parseResult.Data, deserializer, request.RequestId);
return new WebCallResult<T>(response.StatusCode, response.ResponseHeaders, ClientOptions.OutputOriginalData ? data: null, deserializeResult.Data, deserializeResult.Error);
return new WebCallResult<T>(response.StatusCode, response.ResponseHeaders, ClientOptions.OutputOriginalData ? data: null, request.Uri.ToString(), request.Content, request.Method, request.GetHeaders(), deserializeResult.Data, deserializeResult.Error);
}
else
{
@ -214,7 +214,7 @@ namespace CryptoExchange.Net
responseStream.Close();
response.Close();
return new WebCallResult<T>(statusCode, headers, ClientOptions.OutputOriginalData ? desResult.OriginalData : null, desResult.Data, desResult.Error);
return new WebCallResult<T>(statusCode, headers, ClientOptions.OutputOriginalData ? desResult.OriginalData : null, request.Uri.ToString(), request.Content, request.Method, request.GetHeaders(), desResult.Data, desResult.Error);
}
}
else
@ -229,7 +229,7 @@ namespace CryptoExchange.Net
var error = parseResult.Success ? ParseErrorResponse(parseResult.Data) : parseResult.Error!;
if(error.Code == null || error.Code == 0)
error.Code = (int)response.StatusCode;
return new WebCallResult<T>(statusCode, headers, default, error);
return new WebCallResult<T>(statusCode, headers, data, request.Uri.ToString(), request.Content, request.Method, request.GetHeaders(), default, error);
}
}
catch (HttpRequestException requestException)
@ -237,7 +237,7 @@ namespace CryptoExchange.Net
// Request exception, can't reach server for instance
var exceptionInfo = requestException.ToLogString();
log.Write(LogLevel.Warning, $"[{request.RequestId}] Request exception: " + exceptionInfo);
return new WebCallResult<T>(null, null, default, new WebError(exceptionInfo));
return new WebCallResult<T>(null, null, null, request.Uri.ToString(), request.Content, request.Method, request.GetHeaders(), default, new WebError(exceptionInfo));
}
catch (OperationCanceledException canceledException)
{
@ -245,13 +245,13 @@ namespace CryptoExchange.Net
{
// Cancellation token canceled by caller
log.Write(LogLevel.Warning, $"[{request.RequestId}] Request canceled by cancellation token");
return new WebCallResult<T>(null, null, default, new CancellationRequestedError());
return new WebCallResult<T>(null, null, null, request.Uri.ToString(), request.Content, request.Method, request.GetHeaders(), default, new CancellationRequestedError());
}
else
{
// Request timed out
log.Write(LogLevel.Warning, $"[{request.RequestId}] Request timed out: " + canceledException.ToLogString());
return new WebCallResult<T>(null, null, default, new WebError($"[{request.RequestId}] Request timed out"));
return new WebCallResult<T>(null, null, null, request.Uri.ToString(), request.Content, request.Method, request.GetHeaders(), default, new WebError($"[{request.RequestId}] Request timed out"));
}
}
}

View File

@ -163,7 +163,7 @@ namespace CryptoExchange.Net
}
catch (OperationCanceledException)
{
return new CallResult<UpdateSubscription>(null, new CancellationRequestedError());
return new CallResult<UpdateSubscription>(new CancellationRequestedError());
}
try
@ -184,7 +184,7 @@ namespace CryptoExchange.Net
var connectResult = await ConnectIfNeededAsync(socketConnection, authenticated).ConfigureAwait(false);
if (!connectResult)
return new CallResult<UpdateSubscription>(null, connectResult.Error);
return new CallResult<UpdateSubscription>(connectResult.Error!);
if (needsConnecting)
log.Write(LogLevel.Debug, $"Socket {socketConnection.Socket.Id} connected to {url} {(request == null ? "": "with request " + JsonConvert.SerializeObject(request))}");
@ -198,7 +198,7 @@ namespace CryptoExchange.Net
if (socketConnection.PausedActivity)
{
log.Write(LogLevel.Information, $"Socket {socketConnection.Socket.Id} has been paused, can't subscribe at this moment");
return new CallResult<UpdateSubscription>(default, new ServerError("Socket is paused"));
return new CallResult<UpdateSubscription>( new ServerError("Socket is paused"));
}
if (request != null)
@ -208,7 +208,7 @@ namespace CryptoExchange.Net
if (!subResult)
{
await socketConnection.CloseAsync(subscription).ConfigureAwait(false);
return new CallResult<UpdateSubscription>(null, subResult.Error);
return new CallResult<UpdateSubscription>(subResult.Error!);
}
}
else
@ -226,7 +226,7 @@ namespace CryptoExchange.Net
await socketConnection.CloseAsync(subscription).ConfigureAwait(false);
}, false);
}
return new CallResult<UpdateSubscription>(new UpdateSubscription(socketConnection, subscription), null);
return new CallResult<UpdateSubscription>(new UpdateSubscription(socketConnection, subscription));
}
/// <summary>
@ -242,9 +242,15 @@ namespace CryptoExchange.Net
await socketConnection.SendAndWaitAsync(request, ClientOptions.SocketResponseTimeout, data => HandleSubscriptionResponse(socketConnection, subscription, request, data, out callResult)).ConfigureAwait(false);
if (callResult?.Success == true)
{
subscription.Confirmed = true;
return new CallResult<bool>(true);
}
return new CallResult<bool>(callResult?.Success ?? false, callResult == null ? new ServerError("No response on subscription request received"): callResult.Error);
if(callResult== null)
return new CallResult<bool>(new ServerError("No response on subscription request received"));
return new CallResult<bool>(callResult.Error!);
}
/// <summary>
@ -286,7 +292,7 @@ namespace CryptoExchange.Net
var connectResult = await ConnectIfNeededAsync(socketConnection, authenticated).ConfigureAwait(false);
if (!connectResult)
return new CallResult<T>(default, connectResult.Error);
return new CallResult<T>(connectResult.Error!);
}
finally
{
@ -299,7 +305,7 @@ namespace CryptoExchange.Net
if (socketConnection.PausedActivity)
{
log.Write(LogLevel.Information, $"Socket {socketConnection.Socket.Id} has been paused, can't send query at this moment");
return new CallResult<T>(default, new ServerError("Socket is paused"));
return new CallResult<T>(new ServerError("Socket is paused"));
}
return await QueryAndWaitAsync<T>(socketConnection, request).ConfigureAwait(false);
@ -314,7 +320,7 @@ namespace CryptoExchange.Net
/// <returns></returns>
protected virtual async Task<CallResult<T>> QueryAndWaitAsync<T>(SocketConnection socket, object request)
{
var dataResult = new CallResult<T>(default, new ServerError("No response on query received"));
var dataResult = new CallResult<T>(new ServerError("No response on query received"));
await socket.SendAndWaitAsync(request, ClientOptions.SocketResponseTimeout, data =>
{
if (!HandleQueryResponse<T>(socket, request, data, out var callResult))
@ -336,14 +342,14 @@ namespace CryptoExchange.Net
protected virtual async Task<CallResult<bool>> ConnectIfNeededAsync(SocketConnection socket, bool authenticated)
{
if (socket.Connected)
return new CallResult<bool>(true, null);
return new CallResult<bool>(true);
var connectResult = await ConnectSocketAsync(socket).ConfigureAwait(false);
if (!connectResult)
return new CallResult<bool>(false, connectResult.Error);
return new CallResult<bool>(connectResult.Error!);
if (!authenticated || socket.Authenticated)
return new CallResult<bool>(true, null);
return new CallResult<bool>(true);
var result = await AuthenticateSocketAsync(socket).ConfigureAwait(false);
if (!result)
@ -351,11 +357,11 @@ namespace CryptoExchange.Net
await socket.CloseAsync().ConfigureAwait(false);
log.Write(LogLevel.Warning, $"Socket {socket.Socket.Id} authentication failed");
result.Error!.Message = "Authentication failed: " + result.Error.Message;
return new CallResult<bool>(false, result.Error);
return new CallResult<bool>(result.Error);
}
socket.Authenticated = true;
return new CallResult<bool>(true, null);
return new CallResult<bool>(true);
}
/// <summary>
@ -532,11 +538,11 @@ namespace CryptoExchange.Net
if (await socketConnection.Socket.ConnectAsync().ConfigureAwait(false))
{
sockets.TryAdd(socketConnection.Socket.Id, socketConnection);
return new CallResult<bool>(true, null);
return new CallResult<bool>(true);
}
socketConnection.Socket.Dispose();
return new CallResult<bool>(false, new CantConnectError());
return new CallResult<bool>(new CantConnectError());
}
/// <summary>

View File

@ -34,7 +34,7 @@ namespace CryptoExchange.Net
/// <summary>
/// Options for this client
/// </summary>
public RestApiClientOptions Options { get; }
public new RestApiClientOptions Options => (RestApiClientOptions)base.Options;
/// <summary>
/// List of rate limiters
@ -48,8 +48,6 @@ namespace CryptoExchange.Net
/// <param name="apiOptions">The Api client options</param>
public RestApiClient(BaseRestClientOptions options, RestApiClientOptions apiOptions): base(options, apiOptions)
{
Options = apiOptions;
var rateLimiters = new List<IRateLimiter>();
foreach (var rateLimiter in apiOptions.RateLimiters)
rateLimiters.Add(rateLimiter);
@ -70,7 +68,7 @@ namespace CryptoExchange.Net
if (!timeSyncParams.SyncTime || (DateTime.UtcNow - timeSyncParams.TimeSyncState.LastSyncTime < TimeSpan.FromHours(1)))
{
timeSyncParams.TimeSyncState.Semaphore.Release();
return new WebCallResult<bool>(null, null, true, null);
return new WebCallResult<bool>(null, null, null, null, null, null, null, true, null);
}
var localTime = DateTime.UtcNow;
@ -108,7 +106,7 @@ namespace CryptoExchange.Net
}
}
return new WebCallResult<bool>(null, null, true, null);
return new WebCallResult<bool>(null, null, null, null, null, null, null, true, null);
}
}
}

View File

@ -7,11 +7,6 @@ namespace CryptoExchange.Net
/// </summary>
public abstract class SocketApiClient : BaseApiClient
{
/// <summary>
/// The options for this client
/// </summary>
internal ApiClientOptions Options { get; }
/// <summary>
/// ctor
/// </summary>
@ -19,8 +14,6 @@ namespace CryptoExchange.Net
/// <param name="apiOptions">The Api client options</param>
public SocketApiClient(BaseClientOptions options, ApiClientOptions apiOptions): base(options, apiOptions)
{
Options = apiOptions;
}
}
}

View File

@ -1,6 +1,8 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Net;
using System.Net.Http;
namespace CryptoExchange.Net.Objects
{
@ -36,16 +38,6 @@ namespace CryptoExchange.Net.Objects
{
return obj?.Success == true;
}
/// <summary>
/// Create an error result
/// </summary>
/// <param name="error"></param>
/// <returns></returns>
public static WebCallResult CreateErrorResult(Error error)
{
return new WebCallResult(null, null, error);
}
}
/// <summary>
@ -62,22 +54,36 @@ namespace CryptoExchange.Net.Objects
/// <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; set; }
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, Error? error): base(error)
protected 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 erro rto return</param>
public CallResult(Error error) : this(default, null, error) { }
/// <summary>
/// Overwrite bool check so we can use if(callResult) instead of if(callResult.Success)
/// </summary>
@ -111,16 +117,6 @@ namespace CryptoExchange.Net.Objects
}
}
/// <summary>
/// Create an error result
/// </summary>
/// <param name="error"></param>
/// <returns></returns>
public new static WebCallResult<T> CreateErrorResult(Error error)
{
return new WebCallResult<T>(null, null, default, error);
}
/// <summary>
/// Copy the WebCallResult to a new data type
/// </summary>
@ -129,7 +125,18 @@ namespace CryptoExchange.Net.Objects
/// <returns></returns>
public CallResult<K> As<K>([AllowNull] K data)
{
return new CallResult<K>(data, Error);
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);
}
}
@ -154,34 +161,23 @@ namespace CryptoExchange.Net.Objects
/// <param name="code">Status code</param>
/// <param name="responseHeaders">Response headers</param>
/// <param name="error">Error</param>
public WebCallResult(
private WebCallResult(
HttpStatusCode? code,
IEnumerable<KeyValuePair<string, IEnumerable<string>>>? responseHeaders, Error? error) : base(error)
IEnumerable<KeyValuePair<string, IEnumerable<string>>>? responseHeaders,
Error? error) : base(error)
{
ResponseHeaders = responseHeaders;
ResponseStatusCode = code;
}
/// <summary>
/// Create an error result
/// Return the result as an error result
/// </summary>
/// <param name="code">Status code</param>
/// <param name="responseHeaders">Response headers</param>
/// <param name="error">Error</param>
/// <param name="error">The error returned</param>
/// <returns></returns>
public static WebCallResult CreateErrorResult(HttpStatusCode? code, IEnumerable<KeyValuePair<string, IEnumerable<string>>>? responseHeaders, Error error)
public WebCallResult AsError(Error error)
{
return new WebCallResult(code, responseHeaders, error);
}
/// <summary>
/// Create an error result
/// </summary>
/// <param name="result"></param>
/// <returns></returns>
public static WebCallResult CreateErrorResult(WebCallResult result)
{
return new WebCallResult(result.ResponseStatusCode, result.ResponseHeaders, result.Error);
return new WebCallResult(ResponseStatusCode, ResponseHeaders, error);
}
}
@ -191,6 +187,26 @@ namespace CryptoExchange.Net.Objects
/// <typeparam name="T"></typeparam>
public class WebCallResult<T>: CallResult<T>
{
/// <summary>
/// The request http method
/// </summary>
public HttpMethod? RequestMethod { get; set; }
/// <summary>
/// The headers sent with the request
/// </summary>
public IEnumerable<KeyValuePair<string, IEnumerable<string>>>? RequestHeaders { 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>
@ -202,42 +218,47 @@ namespace CryptoExchange.Net.Objects
public IEnumerable<KeyValuePair<string, IEnumerable<string>>>? ResponseHeaders { get; set; }
/// <summary>
/// ctor
/// The time between sending the request and receiving the response
/// </summary>
/// <param name="code"></param>
/// <param name="responseHeaders"></param>
/// <param name="data"></param>
/// <param name="error"></param>
public WebCallResult(
HttpStatusCode? code,
IEnumerable<KeyValuePair<string, IEnumerable<string>>>? responseHeaders,
[AllowNull] T data,
Error? error): base(data, error)
{
ResponseStatusCode = code;
ResponseHeaders = responseHeaders;
}
public TimeSpan? ResponseTime { get; set; }
/// <summary>
/// ctor
/// Create a new result
/// </summary>
/// <param name="code"></param>
/// <param name="originalData"></param>
/// <param name="responseHeaders"></param>
/// <param name="originalData"></param>
/// <param name="requestUrl"></param>
/// <param name="requestBody"></param>
/// <param name="requestMethod"></param>
/// <param name="requestHeaders"></param>
/// <param name="data"></param>
/// <param name="error"></param>
public WebCallResult(
HttpStatusCode? code,
IEnumerable<KeyValuePair<string, IEnumerable<string>>>? responseHeaders,
string? originalData,
string? requestUrl,
string? requestBody,
HttpMethod? requestMethod,
IEnumerable<KeyValuePair<string, IEnumerable<string>>>? requestHeaders,
[AllowNull] T data,
Error? error) : base(data, error)
Error? error) : base(data, originalData, error)
{
OriginalData = originalData;
ResponseStatusCode = code;
ResponseHeaders = responseHeaders;
RequestUrl = requestUrl;
RequestBody = requestBody;
RequestHeaders = requestHeaders;
RequestMethod = requestMethod;
}
/// <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, default, error) { }
/// <summary>
/// Copy the WebCallResult to a new data type
/// </summary>
@ -246,19 +267,18 @@ namespace CryptoExchange.Net.Objects
/// <returns></returns>
public new WebCallResult<K> As<K>([AllowNull] K data)
{
return new WebCallResult<K>(ResponseStatusCode, ResponseHeaders, OriginalData, data, Error);
return new WebCallResult<K>(ResponseStatusCode, ResponseHeaders, OriginalData, RequestUrl, RequestBody, RequestMethod, RequestHeaders, data, Error);
}
/// <summary>
/// Create an error result
/// Copy the WebCallResult to a new data type
/// </summary>
/// <param name="code"></param>
/// <param name="responseHeaders"></param>
/// <param name="error"></param>
/// <typeparam name="K">The new type</typeparam>
/// <param name="error">The error returned</param>
/// <returns></returns>
public static WebCallResult<T> CreateErrorResult(HttpStatusCode? code, IEnumerable<KeyValuePair<string, IEnumerable<string>>>? responseHeaders, Error error)
public new WebCallResult<K> AsError<K>(Error error)
{
return new WebCallResult<T>(code, responseHeaders, default, error);
return new WebCallResult<K>(ResponseStatusCode, ResponseHeaders, OriginalData, RequestUrl, RequestBody, RequestMethod, RequestHeaders, default, error);
}
}
}

View File

@ -118,7 +118,7 @@ namespace CryptoExchange.Net.Objects
}
if (endpointLimit?.IgnoreOtherRateLimits == true)
return new CallResult<int>(totalWaitTime, null);
return new CallResult<int>(totalWaitTime);
List<PartialEndpointRateLimiter> partialEndpointLimits;
lock (_limiterLock)
@ -155,7 +155,7 @@ namespace CryptoExchange.Net.Objects
}
if(partialEndpointLimits.Any(p => p.IgnoreOtherRateLimits))
return new CallResult<int>(totalWaitTime, null);
return new CallResult<int>(totalWaitTime);
ApiKeyRateLimiter? apiLimit;
lock (_limiterLock)
@ -195,7 +195,7 @@ namespace CryptoExchange.Net.Objects
}
if ((signed || apiLimit?.OnlyForSignedRequests == false) && apiLimit?.IgnoreTotalRateLimit == true)
return new CallResult<int>(totalWaitTime, null);
return new CallResult<int>(totalWaitTime);
TotalRateLimiter? totalLimit;
lock (_limiterLock)
@ -209,7 +209,7 @@ namespace CryptoExchange.Net.Objects
totalWaitTime += waitResult.Data;
}
return new CallResult<int>(totalWaitTime, null);
return new CallResult<int>(totalWaitTime);
}
private static async Task<CallResult<int>> ProcessTopic(Log log, Limiter historyTopic, string endpoint, int requestWeight, RateLimitingBehaviour limitBehaviour, CancellationToken ct)
@ -221,7 +221,7 @@ namespace CryptoExchange.Net.Objects
}
catch (OperationCanceledException)
{
return new CallResult<int>(0, new CancellationRequestedError());
return new CallResult<int>(new CancellationRequestedError());
}
sw.Stop();
@ -253,7 +253,7 @@ namespace CryptoExchange.Net.Objects
historyTopic.Semaphore.Release();
var msg = $"Request to {endpoint} failed because of rate limit `{historyTopic}`. Current weight: {currentWeight}/{historyTopic.Limit}, request weight: {requestWeight}";
log.Write(LogLevel.Warning, msg);
return new CallResult<int>(thisWaitTime, new RateLimitError(msg));
return new CallResult<int>(new RateLimitError(msg));
}
log.Write(LogLevel.Information, $"Request to {endpoint} waiting {thisWaitTime}ms for rate limit `{historyTopic}`. Current weight: {currentWeight}/{historyTopic.Limit}, request weight: {requestWeight}");
@ -263,7 +263,7 @@ namespace CryptoExchange.Net.Objects
}
catch (OperationCanceledException)
{
return new CallResult<int>(0, new CancellationRequestedError());
return new CallResult<int>(new CancellationRequestedError());
}
totalWaitTime += thisWaitTime;
}
@ -277,7 +277,7 @@ namespace CryptoExchange.Net.Objects
var newTime = DateTime.UtcNow;
historyTopic.Entries.Add(new LimitEntry(newTime, requestWeight));
historyTopic.Semaphore.Release();
return new CallResult<int>(totalWaitTime, null);
return new CallResult<int>(totalWaitTime);
}
internal struct LimitEntry

View File

@ -233,7 +233,7 @@ namespace CryptoExchange.Net.OrderBook
if (!startResult)
{
Status = OrderBookStatus.Disconnected;
return new CallResult<bool>(false, startResult.Error);
return new CallResult<bool>(startResult.Error!);
}
_subscription = startResult.Data;
@ -252,7 +252,7 @@ namespace CryptoExchange.Net.OrderBook
_subscription.ConnectionRestored += async time => await ResyncAsync().ConfigureAwait(false);
Status = OrderBookStatus.Synced;
return new CallResult<bool>(true, null);
return new CallResult<bool>(true);
}
/// <inheritdoc/>
@ -273,7 +273,7 @@ namespace CryptoExchange.Net.OrderBook
public CallResult<decimal> CalculateAverageFillPrice(decimal quantity, OrderBookEntryType type)
{
if (Status != OrderBookStatus.Synced)
return new CallResult<decimal>(0, new InvalidOperationError($"{nameof(CalculateAverageFillPrice)} is not available when book is not in Synced state"));
return new CallResult<decimal>(new InvalidOperationError($"{nameof(CalculateAverageFillPrice)} is not available when book is not in Synced state"));
var totalCost = 0m;
var totalAmount = 0m;
@ -286,7 +286,7 @@ namespace CryptoExchange.Net.OrderBook
while (amountLeft > 0)
{
if (step == list.Count)
return new CallResult<decimal>(0, new InvalidOperationError("Quantity is larger than order in the order book"));
return new CallResult<decimal>(new InvalidOperationError("Quantity is larger than order in the order book"));
var element = list.ElementAt(step);
var stepAmount = Math.Min(element.Value.Quantity, amountLeft);
@ -297,7 +297,7 @@ namespace CryptoExchange.Net.OrderBook
}
}
return new CallResult<decimal>(Math.Round(totalCost / totalAmount, 8), null);
return new CallResult<decimal>(Math.Round(totalCost / totalAmount, 8));
}
/// <summary>
@ -466,12 +466,12 @@ namespace CryptoExchange.Net.OrderBook
while (!bookSet && Status == OrderBookStatus.Syncing)
{
if ((DateTime.UtcNow - startWait).TotalMilliseconds > timeout)
return new CallResult<bool>(false, new ServerError("Timeout while waiting for data"));
return new CallResult<bool>(new ServerError("Timeout while waiting for data"));
await Task.Delay(10).ConfigureAwait(false);
}
return new CallResult<bool>(true, null);
return new CallResult<bool>(true);
}
/// <summary>

View File

@ -530,7 +530,7 @@ namespace CryptoExchange.Net.Sockets
internal async Task<CallResult<bool>> ResubscribeAsync(SocketSubscription socketSubscription)
{
if (!Socket.IsOpen)
return new CallResult<bool>(false, new UnknownError("Socket is not connected"));
return new CallResult<bool>(new UnknownError("Socket is not connected"));
return await socketClient.SubscribeAndWaitAsync(this, socketSubscription.Request!, socketSubscription).ConfigureAwait(false);
}