mirror of
https://github.com/JKorf/CryptoExchange.Net
synced 2025-12-13 17:20:26 +00:00
wip
This commit is contained in:
parent
99be703f1f
commit
42736f3003
@ -223,7 +223,6 @@ namespace CryptoExchange.Net.Clients
|
||||
string? cacheKey = null;
|
||||
if (ShouldCache(definition))
|
||||
{
|
||||
#warning caching should be static per api client type
|
||||
cacheKey = baseAddress + definition + uriParameters?.ToFormData();
|
||||
_logger.CheckingCache(cacheKey);
|
||||
var cachedValue = _cache.Get(cacheKey, ClientOptions.CachingMaxAge);
|
||||
@ -487,15 +486,14 @@ namespace CryptoExchange.Net.Clients
|
||||
// we'll need to copy it as the stream isn't seekable, and thus we can only read it once
|
||||
var memoryStream = new MemoryStream();
|
||||
await responseStream.CopyToAsync(memoryStream).ConfigureAwait(false);
|
||||
using var reader = new StreamReader(memoryStream, Encoding.UTF8,false, 4096, true);
|
||||
using var reader = new StreamReader(memoryStream, Encoding.UTF8, false, 4096, true);
|
||||
if (outputOriginalData)
|
||||
{
|
||||
memoryStream.Position = 0;
|
||||
originalData = await reader.ReadToEndAsync().ConfigureAwait(false);
|
||||
|
||||
if (_logger.IsEnabled(LogLevel.Trace))
|
||||
#warning TODO extension
|
||||
_logger.LogTrace("[Req {RequestId}] Received response: {Data}", request.RequestId, originalData);
|
||||
_logger.RestApiReceivedResponse(request.RequestId, originalData);
|
||||
}
|
||||
|
||||
// Continue processing from the memory stream since the response stream is already read and we can't seek it
|
||||
|
||||
@ -9,11 +9,13 @@ namespace CryptoExchange.Net.Converters.MessageParsing.DynamicConverters
|
||||
public interface ISocketMessageHandler
|
||||
{
|
||||
/// <summary>
|
||||
/// Get an identifier for the message which can be used to link it to a listener
|
||||
/// Get an identifier for the message which can be used to determine the type of the message
|
||||
/// </summary>
|
||||
//string? GetMessageIdentifier(ReadOnlySpan<byte> data, WebSocketMessageType? webSocketMessageType);
|
||||
|
||||
string? GetTypeIdentifier(ReadOnlySpan<byte> data, WebSocketMessageType? webSocketMessageType);
|
||||
|
||||
/// <summary>
|
||||
/// Get optional topic filter, for example a symbol name
|
||||
/// </summary>
|
||||
string? GetTopicFilter(object deserializedObject);
|
||||
|
||||
/// <summary>
|
||||
|
||||
@ -20,7 +20,7 @@ namespace CryptoExchange.Net.Converters.MessageParsing.DynamicConverters
|
||||
/// <summary>
|
||||
/// The fields this evaluator has to look for
|
||||
/// </summary>
|
||||
public MessageFieldReference[] Fields { get; set; }
|
||||
public MessageFieldReference[] Fields { get; set; } = [];
|
||||
/// <summary>
|
||||
/// The callback for getting the identifier string
|
||||
/// </summary>
|
||||
|
||||
@ -6,6 +6,7 @@ using CryptoExchange.Net.Objects.Options;
|
||||
using CryptoExchange.Net.Requests;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
@ -90,11 +91,19 @@ namespace CryptoExchange.Net.Converters.SystemTextJson.MessageConverters
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
#if NET5_0_OR_GREATER
|
||||
[UnconditionalSuppressMessage("AssemblyLoadTrimming", "IL3050:RequiresUnreferencedCode", Justification = "JsonSerializerOptions provided here has TypeInfoResolver set")]
|
||||
[UnconditionalSuppressMessage("AssemblyLoadTrimming", "IL2026:RequiresUnreferencedCode", Justification = "JsonSerializerOptions provided here has TypeInfoResolver set")]
|
||||
#endif
|
||||
public async ValueTask<(T? Result, Error? Error)> TryDeserializeAsync<T>(Stream responseStream, CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
#pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code
|
||||
#pragma warning disable IL3050 // Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.
|
||||
var result = await JsonSerializer.DeserializeAsync<T>(responseStream, Options)!.ConfigureAwait(false)!;
|
||||
#pragma warning restore IL3050 // Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.
|
||||
#pragma warning restore IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code
|
||||
return (result, null);
|
||||
}
|
||||
catch (JsonException ex)
|
||||
|
||||
@ -1,6 +1,10 @@
|
||||
using CryptoExchange.Net.Converters.MessageParsing.DynamicConverters;
|
||||
using System;
|
||||
#if !NETSTANDARD
|
||||
using System.Collections.Frozen;
|
||||
#endif
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Net.WebSockets;
|
||||
using System.Text;
|
||||
@ -31,10 +35,14 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
|
||||
private int _maxSearchDepth;
|
||||
private MessageEvaluator? _topEvaluator;
|
||||
private List<MessageEvalutorFieldReference>? _searchFields;
|
||||
|
||||
private Dictionary<Type, Func<object, string?>> _mapping;
|
||||
private Dictionary<Type, Func<object, string?>>? _baseTypeMapping;
|
||||
private Dictionary<Type, Func<object, string?>>? _mapping;
|
||||
|
||||
/// <summary>
|
||||
/// Add a mapping of a specific object of a type to a specific topic
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type to get topic for</typeparam>
|
||||
/// <param name="mapping">The topic retrieve delegate</param>
|
||||
protected void AddTopicMapping<T>(Func<T, string?> mapping)
|
||||
{
|
||||
_mapping ??= new Dictionary<Type, Func<object, string?>>();
|
||||
@ -126,6 +134,7 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
|
||||
_initialized = true;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual string? GetTopicFilter(object deserializedObject)
|
||||
{
|
||||
if (_mapping == null)
|
||||
@ -260,22 +269,30 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
|
||||
}
|
||||
else
|
||||
{
|
||||
if (reader.TokenType == JsonTokenType.Number)
|
||||
switch (reader.TokenType)
|
||||
{
|
||||
case JsonTokenType.Number:
|
||||
value = reader.GetDecimal().ToString();
|
||||
else if (reader.TokenType == JsonTokenType.String)
|
||||
break;
|
||||
case JsonTokenType.String:
|
||||
value = reader.GetString()!;
|
||||
else if (reader.TokenType == JsonTokenType.True
|
||||
|| reader.TokenType == JsonTokenType.False)
|
||||
break;
|
||||
case JsonTokenType.True:
|
||||
case JsonTokenType.False:
|
||||
value = reader.GetBoolean().ToString()!;
|
||||
else if (reader.TokenType == JsonTokenType.Null)
|
||||
break;
|
||||
case JsonTokenType.Null:
|
||||
value = null;
|
||||
else if (reader.TokenType == JsonTokenType.StartObject
|
||||
|| reader.TokenType == JsonTokenType.StartArray)
|
||||
break;
|
||||
case JsonTokenType.StartObject:
|
||||
case JsonTokenType.StartArray:
|
||||
value = null;
|
||||
else
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (field.Field.Constraint != null
|
||||
&& !field.Field.Constraint(value))
|
||||
@ -321,6 +338,10 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
#if NET5_0_OR_GREATER
|
||||
[UnconditionalSuppressMessage("AssemblyLoadTrimming", "IL3050:RequiresUnreferencedCode", Justification = "JsonSerializerOptions provided here has TypeInfoResolver set")]
|
||||
[UnconditionalSuppressMessage("AssemblyLoadTrimming", "IL2026:RequiresUnreferencedCode", Justification = "JsonSerializerOptions provided here has TypeInfoResolver set")]
|
||||
#endif
|
||||
public virtual object Deserialize(ReadOnlySpan<byte> data, Type type)
|
||||
{
|
||||
#pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code
|
||||
|
||||
@ -29,6 +29,9 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
|
||||
/// </summary>
|
||||
protected abstract string? GetTypeIdentifier(JsonDocument document);
|
||||
|
||||
/// <summary>
|
||||
/// Get optional topic filter, for example a symbol name
|
||||
/// </summary>
|
||||
public virtual string? GetTopicFilter(object deserializedObject) => null;
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@ -28,6 +28,9 @@ namespace CryptoExchange.Net.Interfaces
|
||||
/// Handle a message
|
||||
/// </summary>
|
||||
CallResult Handle(SocketConnection connection, DateTime receiveTime, string? originalData, object result, MessageHandlerLink matchedHandler);
|
||||
/// <summary>
|
||||
/// Handle a message
|
||||
/// </summary>
|
||||
CallResult Handle(SocketConnection connection, DateTime receiveTime, string? originalData, object result, MessageRoute route);
|
||||
/// <summary>
|
||||
/// Deserialize a message into object of type
|
||||
|
||||
@ -22,6 +22,7 @@ namespace CryptoExchange.Net.Logging.Extensions
|
||||
private static readonly Action<ILogger, string, Exception?> _restApiCacheHit;
|
||||
private static readonly Action<ILogger, string, Exception?> _restApiCacheNotHit;
|
||||
private static readonly Action<ILogger, int?, Exception?> _restApiCancellationRequested;
|
||||
private static readonly Action<ILogger, int?, string?, Exception?> _restApiReceivedResponse;
|
||||
|
||||
static RestApiClientLoggingExtensions()
|
||||
{
|
||||
@ -90,6 +91,11 @@ namespace CryptoExchange.Net.Logging.Extensions
|
||||
new EventId(4012, "RestApiCancellationRequested"),
|
||||
"[Req {RequestId}] Request cancelled by user");
|
||||
|
||||
_restApiReceivedResponse = LoggerMessage.Define<int?, string?>(
|
||||
LogLevel.Trace,
|
||||
new EventId(4013, "RestApiReceivedResponse"),
|
||||
"[Req {RequestId}] Received response: {Data}");
|
||||
|
||||
}
|
||||
|
||||
public static void RestApiErrorReceived(this ILogger logger, int? requestId, HttpStatusCode? responseStatusCode, long responseTime, string? error, string? originalData, Exception? exception)
|
||||
@ -155,5 +161,10 @@ namespace CryptoExchange.Net.Logging.Extensions
|
||||
{
|
||||
_restApiCancellationRequested(logger, requestId, null);
|
||||
}
|
||||
|
||||
public static void RestApiReceivedResponse(this ILogger logger, int requestId, string? originalData)
|
||||
{
|
||||
_restApiReceivedResponse(logger, requestId, originalData, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -214,13 +214,9 @@ namespace CryptoExchange.Net.Sockets
|
||||
if (_ctsSource.IsCancellationRequested || !_processing)
|
||||
return false;
|
||||
|
||||
#warning todo logging overloads without id
|
||||
_logger.SocketAddingBytesToSendBuffer(Id, 0, data);
|
||||
|
||||
try
|
||||
{
|
||||
await _socket!.SendAsync(new ArraySegment<byte>(data, 0, data.Length), type, true, _ctsSource.Token).ConfigureAwait(false);
|
||||
_logger.SocketSentBytes(Id, 0, data.Length);
|
||||
return true;
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
|
||||
@ -10,14 +10,17 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace CryptoExchange.Net.Sockets
|
||||
{
|
||||
/// <summary>
|
||||
/// Message router
|
||||
/// </summary>
|
||||
public class MessageRouter
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// The routes registered for this router
|
||||
/// </summary>
|
||||
public MessageRoute[] Routes { get; }
|
||||
|
||||
// <summary>
|
||||
/// <summary>
|
||||
/// ctor
|
||||
/// </summary>
|
||||
private MessageRouter(params MessageRoute[] routes)
|
||||
@ -26,7 +29,7 @@ namespace CryptoExchange.Net.Sockets
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create message matcher
|
||||
/// Create message router without specific message handler
|
||||
/// </summary>
|
||||
public static MessageRouter CreateWithoutHandler<T>(string typeIdentifier)
|
||||
{
|
||||
@ -34,15 +37,7 @@ namespace CryptoExchange.Net.Sockets
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create message matcher
|
||||
/// </summary>
|
||||
public static MessageRouter CreateWithoutTopicFilter<T>(IEnumerable<string> values, Func<SocketConnection, DateTime, string?, T, CallResult> handler)
|
||||
{
|
||||
return new MessageRouter(values.Select(x => new MessageRoute<T>(x, (string?)null, handler)).ToArray());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create message matcher
|
||||
/// Create message router without specific message handler
|
||||
/// </summary>
|
||||
public static MessageRouter CreateWithoutHandler<T>(string typeIdentifier, string topicFilter)
|
||||
{
|
||||
@ -50,7 +45,15 @@ namespace CryptoExchange.Net.Sockets
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create message matcher
|
||||
/// Create message router without topic filter
|
||||
/// </summary>
|
||||
public static MessageRouter CreateWithoutTopicFilter<T>(IEnumerable<string> values, Func<SocketConnection, DateTime, string?, T, CallResult> handler)
|
||||
{
|
||||
return new MessageRouter(values.Select(x => new MessageRoute<T>(x, (string?)null, handler)).ToArray());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create message router without topic filter
|
||||
/// </summary>
|
||||
public static MessageRouter CreateWithoutTopicFilter<T>(string typeIdentifier, Func<SocketConnection, DateTime, string?, T, CallResult> handler)
|
||||
{
|
||||
@ -58,7 +61,7 @@ namespace CryptoExchange.Net.Sockets
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create message matcher
|
||||
/// Create message router with topic filter
|
||||
/// </summary>
|
||||
public static MessageRouter CreateWithTopicFilter<T>(string typeIdentifier, string topicFilter, Func<SocketConnection, DateTime, string?, T, CallResult> handler)
|
||||
{
|
||||
@ -66,7 +69,7 @@ namespace CryptoExchange.Net.Sockets
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create message matcher
|
||||
/// Create message router with topic filter
|
||||
/// </summary>
|
||||
public static MessageRouter CreateWithTopicFilter<T>(IEnumerable<string> typeIdentifiers, string topicFilter, Func<SocketConnection, DateTime, string?, T, CallResult> handler)
|
||||
{
|
||||
@ -78,7 +81,34 @@ namespace CryptoExchange.Net.Sockets
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create message matcher
|
||||
/// Create message router with topic filter
|
||||
/// </summary>
|
||||
public static MessageRouter CreateWithTopicFilters<T>(string typeIdentifier, IEnumerable<string> topicFilters, Func<SocketConnection, DateTime, string?, T, CallResult> handler)
|
||||
{
|
||||
var routes = new List<MessageRoute>();
|
||||
foreach (var filter in topicFilters)
|
||||
routes.Add(new MessageRoute<T>(typeIdentifier, filter, handler));
|
||||
|
||||
return new MessageRouter(routes.ToArray());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create message router with topic filter
|
||||
/// </summary>
|
||||
public static MessageRouter CreateWithTopicFilters<T>(IEnumerable<string> typeIdentifiers, IEnumerable<string> topicFilters, Func<SocketConnection, DateTime, string?, T, CallResult> handler)
|
||||
{
|
||||
var routes = new List<MessageRoute>();
|
||||
foreach (var type in typeIdentifiers)
|
||||
{
|
||||
foreach (var filter in topicFilters)
|
||||
routes.Add(new MessageRoute<T>(type, filter, handler));
|
||||
}
|
||||
|
||||
return new MessageRouter(routes.ToArray());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create message router with optional topic filter
|
||||
/// </summary>
|
||||
public static MessageRouter CreateWithOptionalTopicFilter<T>(string typeIdentifier, string? topicFilter, Func<SocketConnection, DateTime, string?, T, CallResult> handler)
|
||||
{
|
||||
@ -86,7 +116,7 @@ namespace CryptoExchange.Net.Sockets
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create message matcher
|
||||
/// Create message router with optional topic filter
|
||||
/// </summary>
|
||||
public static MessageRouter CreateWithOptionalTopicFilters<T>(string typeIdentifier, IEnumerable<string>? topicFilters, Func<SocketConnection, DateTime, string?, T, CallResult> handler)
|
||||
{
|
||||
@ -105,7 +135,7 @@ namespace CryptoExchange.Net.Sockets
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create message matcher
|
||||
/// Create message router with optional topic filter
|
||||
/// </summary>
|
||||
public static MessageRouter CreateWithOptionalTopicFilters<T>(IEnumerable<string> typeIdentifiers, IEnumerable<string>? topicFilters, Func<SocketConnection, DateTime, string?, T, CallResult> handler)
|
||||
{
|
||||
@ -127,55 +157,40 @@ namespace CryptoExchange.Net.Sockets
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create message matcher
|
||||
/// Create message matcher with specific routes
|
||||
/// </summary>
|
||||
public static MessageRouter CreateWithTopicFilters<T>(string typeIdentifier, IEnumerable<string> topicFilters, Func<SocketConnection, DateTime, string?, T, CallResult> handler)
|
||||
public static MessageRouter Create(params MessageRoute[] routes)
|
||||
{
|
||||
var routes = new List<MessageRoute>();
|
||||
foreach (var filter in topicFilters)
|
||||
routes.Add(new MessageRoute<T>(typeIdentifier, filter, handler));
|
||||
|
||||
return new MessageRouter(routes.ToArray());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create message matcher
|
||||
/// </summary>
|
||||
public static MessageRouter CreateWithTopicFilters<T>(IEnumerable<string> typeIdentifiers, IEnumerable<string> topicFilters, Func<SocketConnection, DateTime, string?, T, CallResult> handler)
|
||||
{
|
||||
var routes = new List<MessageRoute>();
|
||||
foreach(var type in typeIdentifiers)
|
||||
{
|
||||
foreach (var filter in topicFilters)
|
||||
routes.Add(new MessageRoute<T>(type, filter, handler));
|
||||
}
|
||||
|
||||
return new MessageRouter(routes.ToArray());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create message matcher
|
||||
/// </summary>
|
||||
public static MessageRouter Create(params MessageRoute[] linkers)
|
||||
{
|
||||
return new MessageRouter(linkers);
|
||||
return new MessageRouter(routes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether this matcher contains a specific link
|
||||
/// </summary>
|
||||
public bool ContainsCheck(MessageRoute link) => Routes.Any(x => x.TypeIdentifier == link.TypeIdentifier && x.TopicFilter == link.TopicFilter);
|
||||
public bool ContainsCheck(MessageRoute route) => Routes.Any(x => x.TypeIdentifier == route.TypeIdentifier && x.TopicFilter == route.TopicFilter);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Message route
|
||||
/// </summary>
|
||||
public abstract class MessageRoute
|
||||
{
|
||||
/// <summary>
|
||||
/// Type identifier
|
||||
/// </summary>
|
||||
public string TypeIdentifier { get; set; }
|
||||
/// <summary>
|
||||
/// Optional topic filter
|
||||
/// </summary>
|
||||
public string? TopicFilter { get; set; }
|
||||
/// <summary>
|
||||
/// Deserialization type
|
||||
/// </summary>
|
||||
public abstract Type DeserializationType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// ctor
|
||||
/// </summary>
|
||||
public MessageRoute(string typeIdentifier, string? topicFilter)
|
||||
{
|
||||
TypeIdentifier = typeIdentifier;
|
||||
@ -188,6 +203,9 @@ namespace CryptoExchange.Net.Sockets
|
||||
public abstract CallResult Handle(SocketConnection connection, DateTime receiveTime, string? originalData, object data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Message route
|
||||
/// </summary>
|
||||
public class MessageRoute<TMessage> : MessageRoute
|
||||
{
|
||||
private Func<SocketConnection, DateTime, string?, TMessage, CallResult> _handler;
|
||||
@ -204,16 +222,25 @@ namespace CryptoExchange.Net.Sockets
|
||||
_handler = handler;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create route without topic filter
|
||||
/// </summary>
|
||||
public static MessageRoute<TMessage> CreateWithoutTopicFilter(string typeIdentifier, Func<SocketConnection, DateTime, string?, TMessage, CallResult> handler)
|
||||
{
|
||||
return new MessageRoute<TMessage>(typeIdentifier, null, handler);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create route with optional topic filter
|
||||
/// </summary>
|
||||
public static MessageRoute<TMessage> CreateWithOptionalTopicFilter(string typeIdentifier, string? topicFilter, Func<SocketConnection, DateTime, string?, TMessage, CallResult> handler)
|
||||
{
|
||||
return new MessageRoute<TMessage>(typeIdentifier, topicFilter, handler);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create route with topic filter
|
||||
/// </summary>
|
||||
public static MessageRoute<TMessage> CreateWithTopicFilter(string typeIdentifier, string topicFilter, Func<SocketConnection, DateTime, string?, TMessage, CallResult> handler)
|
||||
{
|
||||
return new MessageRoute<TMessage>(typeIdentifier, topicFilter, handler);
|
||||
|
||||
@ -108,7 +108,9 @@ namespace CryptoExchange.Net.Sockets
|
||||
/// <summary>
|
||||
/// ctor
|
||||
/// </summary>
|
||||
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable.
|
||||
public Query(object request, bool authenticated, int weight = 1)
|
||||
#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable.
|
||||
{
|
||||
_event = new AsyncResetEvent(false, false);
|
||||
|
||||
@ -163,6 +165,10 @@ namespace CryptoExchange.Net.Sockets
|
||||
/// Handle a response message
|
||||
/// </summary>
|
||||
public abstract CallResult Handle(SocketConnection connection, DateTime receiveTime, string? originalData, object message, MessageHandlerLink check);
|
||||
|
||||
/// <summary>
|
||||
/// Handle a response message
|
||||
/// </summary>
|
||||
public abstract CallResult Handle(SocketConnection connection, DateTime receiveTime, string? originalData, object message, MessageRoute route);
|
||||
|
||||
}
|
||||
@ -192,6 +198,7 @@ namespace CryptoExchange.Net.Sockets
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override CallResult Handle(SocketConnection connection, DateTime receiveTime, string? originalData, object message, MessageRoute route)
|
||||
{
|
||||
if (!PreCheckMessage(connection, message))
|
||||
|
||||
@ -535,25 +535,7 @@ namespace CryptoExchange.Net.Sockets
|
||||
_logger.ReceivedData(SocketId, originalData);
|
||||
}
|
||||
|
||||
|
||||
// Current:
|
||||
// 1. Get message identifier
|
||||
// 2. Look for matching handlers and grab the type
|
||||
// 3. Deserialize
|
||||
// 4. Dispatch
|
||||
// Listen id: kline-ethusdt-1m
|
||||
|
||||
// Update:
|
||||
// 1. Get message type identifier
|
||||
// 2. Look for matching handlers and grab the type
|
||||
// 3. Deserialize
|
||||
// 4. Get message topic filter from deserialized type
|
||||
// 5. Dispatch to filtered
|
||||
// Type id: kline
|
||||
// Topic filter: ethusdt-1m
|
||||
|
||||
var typeIdentifier = messageConverter.GetTypeIdentifier(data, type);
|
||||
//var messageIdentifier = messageConverter.GetMessageIdentifier(data, type);
|
||||
if (typeIdentifier == null)
|
||||
{
|
||||
// Both deserialization type and identifier null, can't process
|
||||
|
||||
@ -114,7 +114,9 @@ namespace CryptoExchange.Net.Sockets
|
||||
/// <summary>
|
||||
/// ctor
|
||||
/// </summary>
|
||||
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable.
|
||||
public Subscription(
|
||||
#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable.
|
||||
ILogger logger,
|
||||
bool authenticated,
|
||||
bool userSubscription = true)
|
||||
@ -182,6 +184,9 @@ namespace CryptoExchange.Net.Sockets
|
||||
return matcher.Handle(connection, receiveTime, originalData, data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle an update message
|
||||
/// </summary>
|
||||
public CallResult Handle(SocketConnection connection, DateTime receiveTime, string? originalData, object data, MessageRoute route)
|
||||
{
|
||||
ConnectionInvocations++;
|
||||
|
||||
@ -40,6 +40,13 @@ namespace CryptoExchange.Net.Testing
|
||||
_nestedPropertyForCompare = nestedPropertyForCompare;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validate to subscriptions being established concurrently are indeed handled correctly
|
||||
/// </summary>
|
||||
/// <typeparam name="TUpdate">Type of the subscription update</typeparam>
|
||||
/// <param name="methodInvoke1">Subscription delegate 1</param>
|
||||
/// <param name="methodInvoke2">Subscription delegate 2</param>
|
||||
/// <param name="name">Name</param>
|
||||
public async Task ValidateConcurrentAsync<TUpdate>(
|
||||
Func<TClient, Action<DataEvent<TUpdate>>, Task<CallResult<UpdateSubscription>>> methodInvoke1,
|
||||
Func<TClient, Action<DataEvent<TUpdate>>, Task<CallResult<UpdateSubscription>>> methodInvoke2,
|
||||
@ -120,7 +127,7 @@ namespace CryptoExchange.Net.Testing
|
||||
{
|
||||
var match = matches[0];
|
||||
var prevMessage = line1[1] == '1' ? lastMessage1 : lastMessage2;
|
||||
var json = JsonDocument.Parse(prevMessage);
|
||||
var json = JsonDocument.Parse(prevMessage!);
|
||||
var propName = match.Value.Substring(1, match.Value.Length - 2);
|
||||
var split = propName.Split('.');
|
||||
var jsonProp = json.RootElement;
|
||||
@ -141,7 +148,7 @@ namespace CryptoExchange.Net.Testing
|
||||
{
|
||||
var match = matches[0];
|
||||
var prevMessage = line1[1] == '1' ? lastMessage1 : lastMessage2;
|
||||
var json = JsonDocument.Parse(prevMessage);
|
||||
var json = JsonDocument.Parse(prevMessage!);
|
||||
var propName = match.Value.Substring(1, match.Value.Length - 2);
|
||||
var split = propName.Split('.');
|
||||
var jsonProp = json.RootElement;
|
||||
@ -164,8 +171,6 @@ namespace CryptoExchange.Net.Testing
|
||||
|
||||
if (updates1 != 1 || updates2 != 1)
|
||||
throw new Exception($"Expected 1 update for both subscriptions, instead got {updates1} and {updates2}");
|
||||
|
||||
//await _client.UnsubscribeAllAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user