1
0
mirror of https://github.com/JKorf/CryptoExchange.Net synced 2026-02-16 22:23:54 +00:00
This commit is contained in:
JKorf 2025-12-07 21:21:53 +01:00
parent 42736f3003
commit bb2f6c0a14
4 changed files with 95 additions and 28 deletions

View File

@ -5,40 +5,36 @@ using System.Text;
namespace CryptoExchange.Net.Converters.MessageParsing.DynamicConverters namespace CryptoExchange.Net.Converters.MessageParsing.DynamicConverters
{ {
/// <summary> /// <summary>
/// Message evaluator /// Message type definition
/// </summary> /// </summary>
public class MessageEvaluator public class MessageTypeDefinition
{ {
/// <summary> /// <summary>
/// The priority of this evaluator, higher prio evaluators (with lower Priority number) will be checked for matches before lower ones /// Whether to immediately select the definition when it is matched. Can only be used when the evaluator has a single unique field to look for
/// </summary>
public int Priority { get; set; }
/// <summary>
/// Whether to immediately match the evaluator when it is matched. Can only be used when the evaluator has a single unique field to look for
/// </summary> /// </summary>
public bool ForceIfFound { get; set; } public bool ForceIfFound { get; set; }
/// <summary> /// <summary>
/// The fields this evaluator has to look for /// The fields a message needs to contain for this definition
/// </summary> /// </summary>
public MessageFieldReference[] Fields { get; set; } = []; public MessageFieldReference[] Fields { get; set; } = [];
/// <summary> /// <summary>
/// The callback for getting the identifier string /// The callback for getting the identifier string
/// </summary> /// </summary>
public Func<SearchResult, string>? IdentifyMessageCallback { get; set; } public Func<SearchResult, string>? TypeIdentifierCallback { get; set; }
/// <summary> /// <summary>
/// The static identifier string to return when this evaluator is matched /// The static identifier string to return when this evaluator is matched
/// </summary> /// </summary>
public string? StaticIdentifier { get; set; } public string? StaticIdentifier { get; set; }
internal string? IdentifyMessage(SearchResult result) internal string? GetMessageType(SearchResult result)
{ {
if (StaticIdentifier != null) if (StaticIdentifier != null)
return StaticIdentifier; return StaticIdentifier;
return IdentifyMessageCallback!(result); return TypeIdentifierCallback!(result);
} }
internal bool Statisfied(SearchResult result) internal bool Satisfied(SearchResult result)
{ {
foreach(var field in Fields) foreach(var field in Fields)
{ {

View File

@ -9,7 +9,7 @@ namespace CryptoExchange.Net.Converters.MessageParsing.DynamicConverters
public bool SkipReading { get; set; } public bool SkipReading { get; set; }
public bool OverlappingField { get; set; } public bool OverlappingField { get; set; }
public MessageFieldReference Field { get; set; } public MessageFieldReference Field { get; set; }
public MessageEvaluator? ForceEvaluator { get; set; } public MessageTypeDefinition? ForceEvaluator { get; set; }
public MessageEvalutorFieldReference(MessageFieldReference field) public MessageEvalutorFieldReference(MessageFieldReference field)
{ {

View File

@ -20,7 +20,82 @@ namespace CryptoExchange.Net.Converters.MessageParsing.DynamicConverters
/// <summary> /// <summary>
/// Callback to check if the field value matches an expected constraint /// Callback to check if the field value matches an expected constraint
/// </summary> /// </summary>
public Func<string?, bool>? Constraint { get; set; } public Func<string?, bool>? Constraint { get; private set; }
/// <summary>
/// Check whether the value is one of the string values in the set
/// </summary>
public MessageFieldReference WithFilterContstraint(HashSet<string?> set)
{
Constraint = set.Contains;
return this;
}
/// <summary>
/// Check whether the value is equal to a string
/// </summary>
public MessageFieldReference WithEqualContstraint(string compare)
{
Constraint = x => x != null && x.Equals(compare, StringComparison.Ordinal);
return this;
}
/// <summary>
/// Check whether the value is not equal to a string
/// </summary>
public MessageFieldReference WithNotEqualContstraint(string compare)
{
Constraint = x => x == null || !x.Equals(compare, StringComparison.Ordinal);
return this;
}
/// <summary>
/// Check whether the value is not null
/// </summary>
public MessageFieldReference WithNotNullContstraint()
{
Constraint = x => x != null;
return this;
}
/// <summary>
/// Check whether the value starts with a certain string
/// </summary>
public MessageFieldReference WithStartsWithContstraint(string start)
{
Constraint = x => x != null && x.StartsWith(start, StringComparison.Ordinal);
return this;
}
/// <summary>
/// Check whether the value starts with a certain string
/// </summary>
public MessageFieldReference WithStartsWithContstraints(params string[] startValues)
{
Constraint = x =>
{
if (x == null)
return false;
foreach (var item in startValues)
{
if (x!.StartsWith(item, StringComparison.Ordinal))
return true;
}
return false;
};
return this;
}
/// <summary>
/// Check whether the value starts with a certain string
/// </summary>
public MessageFieldReference WithCustomContstraint(Func<string?, bool> constraint)
{
Constraint = constraint;
return this;
}
/// <summary> /// <summary>
/// ctor /// ctor

View File

@ -1,8 +1,5 @@
using CryptoExchange.Net.Converters.MessageParsing.DynamicConverters; using CryptoExchange.Net.Converters.MessageParsing.DynamicConverters;
using System; using System;
#if !NETSTANDARD
using System.Collections.Frozen;
#endif
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Linq; using System.Linq;
@ -22,18 +19,17 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
/// </summary> /// </summary>
public abstract JsonSerializerOptions Options { get; } public abstract JsonSerializerOptions Options { get; }
/// <summary> /// <summary>
/// Message evaluators /// Message evaluators
/// </summary> /// </summary>
protected abstract MessageEvaluator[] TypeEvaluators { get; } protected abstract MessageTypeDefinition[] TypeEvaluators { get; }
private readonly SearchResult _searchResult = new(); private readonly SearchResult _searchResult = new();
private bool _hasArraySearches; private bool _hasArraySearches;
private bool _initialized; private bool _initialized;
private int _maxSearchDepth; private int _maxSearchDepth;
private MessageEvaluator? _topEvaluator; private MessageTypeDefinition? _topEvaluator;
private List<MessageEvalutorFieldReference>? _searchFields; private List<MessageEvalutorFieldReference>? _searchFields;
private Dictionary<Type, Func<object, string?>>? _baseTypeMapping; private Dictionary<Type, Func<object, string?>>? _baseTypeMapping;
private Dictionary<Type, Func<object, string?>>? _mapping; private Dictionary<Type, Func<object, string?>>? _mapping;
@ -56,7 +52,7 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
_maxSearchDepth = int.MinValue; _maxSearchDepth = int.MinValue;
_searchFields = new List<MessageEvalutorFieldReference>(); _searchFields = new List<MessageEvalutorFieldReference>();
foreach (var evaluator in TypeEvaluators.OrderBy(x => x.Priority)) foreach (var evaluator in TypeEvaluators)
{ {
_topEvaluator ??= evaluator; _topEvaluator ??= evaluator;
foreach (var field in evaluator.Fields) foreach (var field in evaluator.Fields)
@ -105,7 +101,7 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
foreach(var sameSearchField in existingSameSearchField) foreach(var sameSearchField in existingSameSearchField)
{ {
if (sameSearchField.SkipReading == true if (sameSearchField.SkipReading == true
&& (evaluator.IdentifyMessageCallback != null || field.Constraint != null)) && (evaluator.TypeIdentifierCallback != null || field.Constraint != null))
{ {
sameSearchField.SkipReading = false; sameSearchField.SkipReading = false;
} }
@ -121,7 +117,7 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
_searchFields.Add(new MessageEvalutorFieldReference(field) _searchFields.Add(new MessageEvalutorFieldReference(field)
{ {
SkipReading = evaluator.IdentifyMessageCallback == null && field.Constraint == null, SkipReading = evaluator.TypeIdentifierCallback == null && field.Constraint == null,
ForceEvaluator = !existingSameSearchField.Any() ? (evaluator.ForceIfFound ? evaluator : null) : null, ForceEvaluator = !existingSameSearchField.Any() ? (evaluator.ForceIfFound ? evaluator : null) : null,
OverlappingField = overlapping.Any() OverlappingField = overlapping.Any()
}); });
@ -309,7 +305,7 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
return field.ForceEvaluator.StaticIdentifier; return field.ForceEvaluator.StaticIdentifier;
// Force the immediate return upon encountering this field // Force the immediate return upon encountering this field
return field.ForceEvaluator.IdentifyMessage(_searchResult); return field.ForceEvaluator.GetMessageType(_searchResult);
} }
written = true; written = true;
@ -320,8 +316,8 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
if (!written) if (!written)
continue; continue;
if (_topEvaluator!.Statisfied(_searchResult)) if (_topEvaluator!.Satisfied(_searchResult))
return _topEvaluator.IdentifyMessage(_searchResult); return _topEvaluator.GetMessageType(_searchResult);
if (_searchFields.Count == _searchResult.Count) if (_searchFields.Count == _searchResult.Count)
break; break;
@ -330,8 +326,8 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
foreach (var evaluator in TypeEvaluators) foreach (var evaluator in TypeEvaluators)
{ {
if (evaluator.Statisfied(_searchResult)) if (evaluator.Satisfied(_searchResult))
return evaluator.IdentifyMessage(_searchResult); return evaluator.GetMessageType(_searchResult);
} }
return null; return null;