using CryptoExchange.Net.SharedApis; using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Net; using System.Net.Http; using System.Text; namespace CryptoExchange.Net.Objects { /// /// The result of an operation /// public class CallResult { /// /// An error if the call didn't succeed, will always be filled if Success = false /// public Error? Error { get; internal set; } /// /// Whether the call was successful /// public bool Success => Error == null; /// /// ctor /// /// public CallResult(Error? error) { Error = error; } /// /// Overwrite bool check so we can use if(callResult) instead of if(callResult.Success) /// /// public static implicit operator bool(CallResult obj) { return obj?.Success == true; } /// public override string ToString() { return Success ? $"Success" : $"Error: {Error}"; } } /// /// The result of an operation /// /// public class CallResult: CallResult { /// /// The data returned by the call, only available when Success = true /// public T Data { get; internal set; } /// /// The original data returned by the call, only available when `OutputOriginalData` is set to `true` in the client options /// public string? OriginalData { get; internal set; } /// /// ctor /// /// /// /// #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 } /// /// Create a new data result /// /// The data to return public CallResult(T data) : this(data, null, null) { } /// /// Create a new error result /// /// The error to return public CallResult(Error error) : this(default, null, error) { } /// /// Create a new error result /// /// The error to return /// The original response data public CallResult(Error error, string? originalData) : this(default, originalData, error) { } /// /// Overwrite bool check so we can use if(callResult) instead of if(callResult.Success) /// /// public static implicit operator bool(CallResult obj) { return obj?.Success == true; } /// /// Whether the call was successful or not. Useful for nullability checking. /// /// The data returned by the call. /// on failure. /// true when succeeded, false otherwise. public bool GetResultOrError([MaybeNullWhen(false)] out T data, [NotNullWhen(false)] out Error? error) { if (Success) { data = Data!; error = null; return true; } else { data = default; error = Error!; return false; } } /// /// Copy the WebCallResult to a new data type /// /// The new type /// The data of the new type /// public CallResult As([AllowNull] K data) { return new CallResult(data, OriginalData, Error); } /// /// Copy as a dataless result /// /// public CallResult AsDataless() { return new CallResult(null); } /// /// Copy as a dataless result /// /// public CallResult AsDatalessError(Error error) { return new CallResult(error); } /// /// Copy the WebCallResult to a new data type /// /// The new type /// The error to return /// public CallResult AsError(Error error) { return new CallResult(default, OriginalData, error); } /// public override string ToString() { return Success ? $"Success" : $"Error: {Error}"; } } /// /// The result of a request /// public class WebCallResult : CallResult { /// /// The request http method /// public HttpMethod? RequestMethod { get; set; } /// /// The headers sent with the request /// public IEnumerable>>? RequestHeaders { get; set; } /// /// The request id /// public int? RequestId { get; set; } /// /// The url which was requested /// public string? RequestUrl { get; set; } /// /// The body of the request /// public string? RequestBody { get; set; } /// /// The status code of the response. Note that a OK status does not always indicate success, check the Success parameter for this. /// public HttpStatusCode? ResponseStatusCode { get; set; } /// /// The response headers /// public IEnumerable>>? ResponseHeaders { get; set; } /// /// The time between sending the request and receiving the response /// public TimeSpan? ResponseTime { get; set; } /// /// ctor /// /// /// /// /// /// /// /// /// /// public WebCallResult( HttpStatusCode? code, IEnumerable>>? responseHeaders, TimeSpan? responseTime, int? requestId, string? requestUrl, string? requestBody, HttpMethod? requestMethod, IEnumerable>>? requestHeaders, Error? error) : base(error) { ResponseStatusCode = code; ResponseHeaders = responseHeaders; ResponseTime = responseTime; RequestId = requestId; RequestUrl = requestUrl; RequestBody = requestBody; RequestHeaders = requestHeaders; RequestMethod = requestMethod; } /// /// ctor /// /// public WebCallResult(Error error): base(error) { } /// /// Return the result as an error result /// /// The error returned /// public WebCallResult AsError(Error error) { return new WebCallResult(ResponseStatusCode, ResponseHeaders, ResponseTime, RequestId, RequestUrl, RequestBody, RequestMethod, RequestHeaders, error); } /// /// Copy the WebCallResult to a new data type /// /// The new type /// The data of the new type /// public WebCallResult As([AllowNull] K data) { return new WebCallResult(ResponseStatusCode, ResponseHeaders, ResponseTime, 0, null, RequestId, RequestUrl, RequestBody, RequestMethod, RequestHeaders, ResultDataSource.Server, data, Error); } /// /// Copy the WebCallResult to an ExchangeWebResult of a new data type /// /// The new type /// The exchange /// Trade mode the result applies to /// The data /// public ExchangeWebResult AsExchangeResult(string exchange, TradingMode tradeMode, [AllowNull] K data) { return new ExchangeWebResult(exchange, tradeMode, this.As(data)); } /// /// Copy the WebCallResult to an ExchangeWebResult of a new data type /// /// The new type /// The exchange /// Trade modes the result applies to /// The data /// public ExchangeWebResult AsExchangeResult(string exchange, TradingMode[]? tradeModes, [AllowNull] K data) { return new ExchangeWebResult(exchange, tradeModes, this.As(data)); } /// /// Copy the WebCallResult to a new data type /// /// The new type /// The error returned /// public WebCallResult AsError(Error error) { return new WebCallResult(ResponseStatusCode, ResponseHeaders, ResponseTime, 0, null, RequestId, RequestUrl, RequestBody, RequestMethod, RequestHeaders, ResultDataSource.Server, default, error); } /// public override string ToString() { return (Success ? $"Success" : $"Error: {Error}") + $" in {ResponseTime}"; } } /// /// The result of a request /// /// public class WebCallResult: CallResult { /// /// The request http method /// public HttpMethod? RequestMethod { get; set; } /// /// The headers sent with the request /// public IEnumerable>>? RequestHeaders { get; set; } /// /// The request id /// public int? RequestId { get; set; } /// /// The url which was requested /// public string? RequestUrl { get; set; } /// /// The body of the request /// public string? RequestBody { get; set; } /// /// The status code of the response. Note that a OK status does not always indicate success, check the Success parameter for this. /// public HttpStatusCode? ResponseStatusCode { get; set; } /// /// Length in bytes of the response /// public long? ResponseLength { get; set; } /// /// The response headers /// public IEnumerable>>? ResponseHeaders { get; set; } /// /// The time between sending the request and receiving the response /// public TimeSpan? ResponseTime { get; set; } /// /// The data source of this result /// public ResultDataSource DataSource { get; set; } = ResultDataSource.Server; /// /// Create a new result /// /// /// /// /// /// /// /// /// /// /// /// /// /// public WebCallResult( HttpStatusCode? code, IEnumerable>>? responseHeaders, TimeSpan? responseTime, long? responseLength, string? originalData, int? requestId, string? requestUrl, string? requestBody, HttpMethod? requestMethod, IEnumerable>>? requestHeaders, ResultDataSource dataSource, [AllowNull] T data, Error? error) : base(data, originalData, error) { ResponseStatusCode = code; ResponseHeaders = responseHeaders; ResponseTime = responseTime; ResponseLength = responseLength; RequestId = requestId; RequestUrl = requestUrl; RequestBody = requestBody; RequestHeaders = requestHeaders; RequestMethod = requestMethod; DataSource = dataSource; } /// /// Copy as a dataless result /// /// public new WebCallResult AsDataless() { return new WebCallResult(ResponseStatusCode, ResponseHeaders, ResponseTime, RequestId, RequestUrl, RequestBody, RequestMethod, RequestHeaders, Error); } /// /// Copy as a dataless result /// /// public new WebCallResult AsDatalessError(Error error) { return new WebCallResult(ResponseStatusCode, ResponseHeaders, ResponseTime, RequestId, RequestUrl, RequestBody, RequestMethod, RequestHeaders, error); } /// /// Create a new error result /// /// The error public WebCallResult(Error? error) : this(null, null, null, null, null, null, null, null, null, null, ResultDataSource.Server, default, error) { } /// /// Copy the WebCallResult to a new data type /// /// The new type /// The data of the new type /// public new WebCallResult As([AllowNull] K data) { return new WebCallResult(ResponseStatusCode, ResponseHeaders, ResponseTime, ResponseLength, OriginalData, RequestId, RequestUrl, RequestBody, RequestMethod, RequestHeaders, DataSource, data, Error); } /// /// Copy the WebCallResult to a new data type /// /// The new type /// The error returned /// public new WebCallResult AsError(Error error) { return new WebCallResult(ResponseStatusCode, ResponseHeaders, ResponseTime, ResponseLength, OriginalData, RequestId, RequestUrl, RequestBody, RequestMethod, RequestHeaders, DataSource, default, error); } /// /// Copy the WebCallResult to an ExchangeWebResult of a new data type /// /// The exchange /// Trade mode the result applies to /// public ExchangeWebResult AsExchangeResult(string exchange, TradingMode tradeMode) { return new ExchangeWebResult(exchange, tradeMode, this); } /// /// Copy the WebCallResult to an ExchangeWebResult of a new data type /// /// The exchange /// Trade modes the result applies to /// public ExchangeWebResult AsExchangeResult(string exchange, TradingMode[] tradeModes) { return new ExchangeWebResult(exchange, tradeModes, this); } /// /// Copy the WebCallResult to an ExchangeWebResult of a new data type /// /// The new type /// The exchange /// Trade mode the result applies to /// Data /// Next page token /// public ExchangeWebResult AsExchangeResult(string exchange, TradingMode tradeMode, [AllowNull] K data, INextPageToken? nextPageToken = null) { return new ExchangeWebResult(exchange, tradeMode, As(data), nextPageToken); } /// /// Copy the WebCallResult to an ExchangeWebResult of a new data type /// /// The new type /// The exchange /// Trade modes the result applies to /// Data /// Next page token /// public ExchangeWebResult AsExchangeResult(string exchange, TradingMode[]? tradeModes, [AllowNull] K data, INextPageToken? nextPageToken = null) { return new ExchangeWebResult(exchange, tradeModes, As(data), nextPageToken); } /// /// Copy the WebCallResult to an ExchangeWebResult with a specific error /// /// The new type /// The exchange /// The error returned /// public ExchangeWebResult AsExchangeError(string exchange, Error error) { return new ExchangeWebResult(exchange, null, AsError(error)); } /// /// Return a copy of this result with data source set to cache /// /// internal WebCallResult Cached() { return new WebCallResult(ResponseStatusCode, ResponseHeaders, ResponseTime, ResponseLength, OriginalData, RequestId, RequestUrl, RequestBody, RequestMethod, RequestHeaders, ResultDataSource.Cache, Data, Error); } /// 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(); } } }