mirror of
https://github.com/JKorf/CryptoExchange.Net
synced 2025-12-16 02:41:03 +00:00
wip
This commit is contained in:
parent
839ebc4ca9
commit
fcef172069
@ -1,22 +1,22 @@
|
|||||||
using CryptoExchange.Net.Converters.MessageParsing;
|
//using CryptoExchange.Net.Converters.MessageParsing;
|
||||||
using CryptoExchange.Net.Converters.MessageParsing.DynamicConverters;
|
//using CryptoExchange.Net.Converters.MessageParsing.DynamicConverters;
|
||||||
using CryptoExchange.Net.Objects;
|
//using CryptoExchange.Net.Objects;
|
||||||
using LightProto;
|
//using LightProto;
|
||||||
using System;
|
//using System;
|
||||||
using System.Collections.Generic;
|
//using System.Collections.Generic;
|
||||||
using System.Net.WebSockets;
|
//using System.Net.WebSockets;
|
||||||
using System.Text;
|
//using System.Text;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Protobuf.Converters.Protobuf
|
//namespace CryptoExchange.Net.Protobuf.Converters.Protobuf
|
||||||
{
|
//{
|
||||||
public abstract class DynamicProtobufConverter<T> : ISocketMessageHandler
|
// public abstract class DynamicProtobufConverter<T> : ISocketMessageHandler
|
||||||
{
|
// {
|
||||||
public object Deserialize(ReadOnlySpan<byte> data, Type type)
|
// public object Deserialize(ReadOnlySpan<byte> data, Type type)
|
||||||
{
|
// {
|
||||||
var result = Serializer.Deserialize<T>(data);
|
// var result = Serializer.Deserialize<T>(data);
|
||||||
return result;
|
// return result;
|
||||||
}
|
// }
|
||||||
|
|
||||||
public abstract string GetMessageIdentifier(ReadOnlySpan<byte> data, WebSocketMessageType? webSocketMessageType);
|
// public abstract string GetMessageIdentifier(ReadOnlySpan<byte> data, WebSocketMessageType? webSocketMessageType);
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
|||||||
@ -4,11 +4,6 @@
|
|||||||
<name>CryptoExchange.Net.Protobuf</name>
|
<name>CryptoExchange.Net.Protobuf</name>
|
||||||
</assembly>
|
</assembly>
|
||||||
<members>
|
<members>
|
||||||
<member name="F:CryptoExchange.Net.Protobuf.Converters.Protobuf.DynamicProtobufConverter._model">
|
|
||||||
<summary>
|
|
||||||
Runtime type model
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="T:CryptoExchange.Net.Converters.Protobuf.ProtobufMessageAccessor`1">
|
<member name="T:CryptoExchange.Net.Converters.Protobuf.ProtobufMessageAccessor`1">
|
||||||
<summary>
|
<summary>
|
||||||
System.Text.Json message accessor
|
System.Text.Json message accessor
|
||||||
|
|||||||
@ -486,6 +486,10 @@ namespace CryptoExchange.Net.Clients
|
|||||||
memoryStream.Position = 0;
|
memoryStream.Position = 0;
|
||||||
originalData = await reader.ReadToEndAsync().ConfigureAwait(false);
|
originalData = await reader.ReadToEndAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
|
if (_logger.IsEnabled(LogLevel.Trace))
|
||||||
|
#warning TODO extension
|
||||||
|
_logger.LogTrace("[Req {RequestId}] Received response: {Data}", request.RequestId, originalData);
|
||||||
|
|
||||||
// Continue processing from the memory stream since the response stream is already read and we can't seek it
|
// Continue processing from the memory stream since the response stream is already read and we can't seek it
|
||||||
responseStream.Close();
|
responseStream.Close();
|
||||||
memoryStream.Position = 0;
|
memoryStream.Position = 0;
|
||||||
@ -494,9 +498,12 @@ namespace CryptoExchange.Net.Clients
|
|||||||
|
|
||||||
if (!response.IsSuccessStatusCode && !requestDefinition.TryParseOnNonSuccess)
|
if (!response.IsSuccessStatusCode && !requestDefinition.TryParseOnNonSuccess)
|
||||||
{
|
{
|
||||||
|
// If the response status is not success it is an error by definition
|
||||||
|
|
||||||
Error error;
|
Error error;
|
||||||
if (response.StatusCode == (HttpStatusCode)418 || response.StatusCode == (HttpStatusCode)429)
|
if (response.StatusCode == (HttpStatusCode)418 || response.StatusCode == (HttpStatusCode)429)
|
||||||
{
|
{
|
||||||
|
// Specifically handle rate limit errors
|
||||||
var rateError = await MessageHandler.ParseErrorRateLimitResponse(
|
var rateError = await MessageHandler.ParseErrorRateLimitResponse(
|
||||||
(int)response.StatusCode,
|
(int)response.StatusCode,
|
||||||
state,
|
state,
|
||||||
@ -512,6 +519,7 @@ namespace CryptoExchange.Net.Clients
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// Handle a 'normal' error response. Can still be either a json error message or some random HTML or other string
|
||||||
error = await MessageHandler.ParseErrorResponse(
|
error = await MessageHandler.ParseErrorResponse(
|
||||||
(int)response.StatusCode,
|
(int)response.StatusCode,
|
||||||
state,
|
state,
|
||||||
@ -526,7 +534,7 @@ namespace CryptoExchange.Net.Clients
|
|||||||
// Success status code and expected empty response, assume it's correct
|
// Success status code and expected empty response, assume it's correct
|
||||||
return new WebCallResult<T>(response.StatusCode, response.HttpVersion, response.ResponseHeaders, sw.Elapsed, 0, originalData, request.RequestId, request.Uri.ToString(), request.Content, request.Method, request.GetHeaders(), ResultDataSource.Server, default, null);
|
return new WebCallResult<T>(response.StatusCode, response.HttpVersion, response.ResponseHeaders, sw.Elapsed, 0, originalData, request.RequestId, request.Uri.ToString(), request.Content, request.Method, request.GetHeaders(), ResultDataSource.Server, default, null);
|
||||||
|
|
||||||
// Data response received
|
// Data response received, inspect the message and check if it is an error or not
|
||||||
var parsedError = await MessageHandler.CheckForErrorResponse(
|
var parsedError = await MessageHandler.CheckForErrorResponse(
|
||||||
requestDefinition,
|
requestDefinition,
|
||||||
state,
|
state,
|
||||||
@ -547,8 +555,17 @@ namespace CryptoExchange.Net.Clients
|
|||||||
return new WebCallResult<T>(response.StatusCode, response.HttpVersion, response.ResponseHeaders, sw.Elapsed, response.ContentLength, originalData, request.RequestId, request.Uri.ToString(), request.Content, request.Method, request.GetHeaders(), ResultDataSource.Server, default, parsedError);
|
return new WebCallResult<T>(response.StatusCode, response.HttpVersion, response.ResponseHeaders, sw.Elapsed, response.ContentLength, originalData, request.RequestId, request.Uri.ToString(), request.Content, request.Method, request.GetHeaders(), ResultDataSource.Server, default, parsedError);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Try deserialization into the expected type
|
||||||
var (deserializeResult, deserializeError) = await MessageHandler.TryDeserializeAsync<T>(responseStream, state, cancellationToken).ConfigureAwait(false);
|
var (deserializeResult, deserializeError) = await MessageHandler.TryDeserializeAsync<T>(responseStream, state, cancellationToken).ConfigureAwait(false);
|
||||||
return new WebCallResult<T>(response.StatusCode, response.HttpVersion, response.ResponseHeaders, sw.Elapsed, response.ContentLength, originalData, request.RequestId, request.Uri.ToString(), request.Content, request.Method, request.GetHeaders(), ResultDataSource.Server, deserializeResult, deserializeError);
|
if (deserializeError != null)
|
||||||
|
return new WebCallResult<T>(response.StatusCode, response.HttpVersion, response.ResponseHeaders, sw.Elapsed, response.ContentLength, originalData, request.RequestId, request.Uri.ToString(), request.Content, request.Method, request.GetHeaders(), ResultDataSource.Server, deserializeResult, deserializeError); ;
|
||||||
|
|
||||||
|
// Check the deserialized response to see if it's an error or not
|
||||||
|
var responseError = MessageHandler.CheckDeserializedResponse(response.ResponseHeaders, deserializeResult);
|
||||||
|
if (responseError != null)
|
||||||
|
return new WebCallResult<T>(response.StatusCode, response.HttpVersion, response.ResponseHeaders, sw.Elapsed, response.ContentLength, originalData, request.RequestId, request.Uri.ToString(), request.Content, request.Method, request.GetHeaders(), ResultDataSource.Server, deserializeResult, responseError);
|
||||||
|
|
||||||
|
return new WebCallResult<T>(response.StatusCode, response.HttpVersion, response.ResponseHeaders, sw.Elapsed, response.ContentLength, originalData, request.RequestId, request.Uri.ToString(), request.Content, request.Method, request.GetHeaders(), ResultDataSource.Server, deserializeResult, null);
|
||||||
}
|
}
|
||||||
catch (HttpRequestException requestException)
|
catch (HttpRequestException requestException)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -44,7 +44,10 @@ namespace CryptoExchange.Net.Converters.MessageParsing.DynamicConverters
|
|||||||
Stream responseStream);
|
Stream responseStream);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Check if the response is an error response; if so return the error
|
/// Check if the response is an error response; if so return the error.<br />
|
||||||
|
/// Note that if the API returns a standard result wrapper, something like this:
|
||||||
|
/// <code>{ "code": 400, "msg": "error", "data": {} }</code>
|
||||||
|
/// then the `CheckDeserializedResponse` method should be used for checking the result
|
||||||
/// </summary>
|
/// </summary>
|
||||||
ValueTask<Error?> CheckForErrorResponse(
|
ValueTask<Error?> CheckForErrorResponse(
|
||||||
RequestDefinition request,
|
RequestDefinition request,
|
||||||
@ -59,6 +62,11 @@ namespace CryptoExchange.Net.Converters.MessageParsing.DynamicConverters
|
|||||||
Stream responseStream,
|
Stream responseStream,
|
||||||
object? state,
|
object? state,
|
||||||
CancellationToken ct);
|
CancellationToken ct);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Check whether the resulting T object indicates an error or not
|
||||||
|
/// </summary>
|
||||||
|
Error? CheckDeserializedResponse<T>(HttpResponseHeaders responseHeaders, T result);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -119,49 +119,18 @@ namespace CryptoExchange.Net.Converters.SystemTextJson.MessageConverters
|
|||||||
}
|
}
|
||||||
return (result, null);
|
return (result, null);
|
||||||
}
|
}
|
||||||
catch (HttpRequestException requestException)
|
catch (JsonException ex)
|
||||||
{
|
{
|
||||||
// Request exception, can't reach server for instance
|
var info = $"Json deserialization failed: {ex.Message}, Path: {ex.Path}, LineNumber: {ex.LineNumber}, LinePosition: {ex.BytePositionInLine}";
|
||||||
var error = new WebError(requestException.Message, requestException);
|
return (default, new DeserializeError(info, ex));
|
||||||
return (default, error);
|
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException canceledException)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
if (cancellationToken != default && canceledException.CancellationToken == cancellationToken)
|
return (default, new DeserializeError($"Json deserialization failed: {ex.Message}", ex));
|
||||||
{
|
|
||||||
// Cancellation token canceled by caller
|
|
||||||
return (default, new CancellationRequestedError(canceledException));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Request timed out
|
|
||||||
var error = new WebError($"Request timed out", exception: canceledException);
|
|
||||||
error.ErrorType = ErrorType.Timeout;
|
|
||||||
return (default, error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (ArgumentException argumentException)
|
|
||||||
{
|
|
||||||
if (argumentException.Message.StartsWith("Only HTTP/"))
|
|
||||||
{
|
|
||||||
// Unsupported HTTP version error .net framework
|
|
||||||
var error = ArgumentError.Invalid(nameof(RestExchangeOptions.HttpVersion), $"Invalid HTTP version: " + argumentException.Message);
|
|
||||||
return (default, error);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
catch (NotSupportedException notSupportedException)
|
|
||||||
{
|
|
||||||
if (notSupportedException.Message.StartsWith("Request version value must be one of"))
|
|
||||||
{
|
|
||||||
// Unsupported HTTP version error dotnet code
|
|
||||||
var error = ArgumentError.Invalid(nameof(RestExchangeOptions.HttpVersion), $"Invalid HTTP version: " + notSupportedException.Message);
|
|
||||||
return (default, error);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public virtual Error? CheckDeserializedResponse<T>(HttpResponseHeaders responseHeaders, T result) => null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -80,11 +80,15 @@ namespace CryptoExchange.Net.Objects
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get the parameter collection based on the ParameterPosition
|
/// Get the parameter collection based on the ParameterPosition
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IDictionary<string, object>? GetPositionParameters()
|
public IDictionary<string, object> GetPositionParameters()
|
||||||
{
|
{
|
||||||
if (ParameterPosition == HttpMethodParameterPosition.InBody)
|
if (ParameterPosition == HttpMethodParameterPosition.InBody)
|
||||||
|
{
|
||||||
|
BodyParameters ??= new Dictionary<string, object>();
|
||||||
return BodyParameters;
|
return BodyParameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryParameters ??= new Dictionary<string, object>();
|
||||||
return QueryParameters;
|
return QueryParameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -565,7 +565,7 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
if (deserializationType == null)
|
if (deserializationType == null)
|
||||||
{
|
{
|
||||||
// No handler found for identifier either, can't process
|
// No handler found for identifier either, can't process
|
||||||
_logger.LogWarning("Failed to determine message type. Data: {Message}", Encoding.UTF8.GetString(data.ToArray()));
|
_logger.LogWarning("Failed to determine message type for identifier {Identifier}. Data: {Message}", messageIdentifier, Encoding.UTF8.GetString(data.ToArray()));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user