1
0
mirror of https://github.com/JKorf/CryptoExchange.Net synced 2026-02-16 14:13:46 +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
{
/// <summary>
/// Message evaluator
/// Message type definition
/// </summary>
public class MessageEvaluator
public class MessageTypeDefinition
{
/// <summary>
/// The priority of this evaluator, higher prio evaluators (with lower Priority number) will be checked for matches before lower ones
/// </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
/// 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 bool ForceIfFound { get; set; }
/// <summary>
/// The fields this evaluator has to look for
/// The fields a message needs to contain for this definition
/// </summary>
public MessageFieldReference[] Fields { get; set; } = [];
/// <summary>
/// The callback for getting the identifier string
/// </summary>
public Func<SearchResult, string>? IdentifyMessageCallback { get; set; }
public Func<SearchResult, string>? TypeIdentifierCallback { get; set; }
/// <summary>
/// The static identifier string to return when this evaluator is matched
/// </summary>
public string? StaticIdentifier { get; set; }
internal string? IdentifyMessage(SearchResult result)
internal string? GetMessageType(SearchResult result)
{
if (StaticIdentifier != null)
return StaticIdentifier;
return IdentifyMessageCallback!(result);
return TypeIdentifierCallback!(result);
}
internal bool Statisfied(SearchResult result)
internal bool Satisfied(SearchResult result)
{
foreach(var field in Fields)
{

View File

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

View File

@ -20,7 +20,82 @@ namespace CryptoExchange.Net.Converters.MessageParsing.DynamicConverters
/// <summary>
/// Callback to check if the field value matches an expected constraint
/// </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>
/// ctor

View File

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