From 84df96429c42e5b6a5d11e88f89eb12a407ab0b1 Mon Sep 17 00:00:00 2001 From: "nicolas.dorier" Date: Fri, 10 May 2024 08:55:53 +0900 Subject: [PATCH] Refactor of Default RateRules --- BTCPayServer.Rating/RateRules.cs | 59 ++++++++++++++++++-------------- BTCPayServer/Data/StoreBlob.cs | 19 ++-------- BTCPayServer/DefaultRates.cs | 11 +++++- 3 files changed, 45 insertions(+), 44 deletions(-) diff --git a/BTCPayServer.Rating/RateRules.cs b/BTCPayServer.Rating/RateRules.cs index 42228207d..472ec56c2 100644 --- a/BTCPayServer.Rating/RateRules.cs +++ b/BTCPayServer.Rating/RateRules.cs @@ -1,7 +1,10 @@ +#nullable enable using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Linq; +using System.Text; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; @@ -29,7 +32,7 @@ namespace BTCPayServer.Rating public List Errors = new List(); bool IsInvocation; - public override SyntaxNode VisitInvocationExpression(InvocationExpressionSyntax node) + public override SyntaxNode? VisitInvocationExpression(InvocationExpressionSyntax node) { if (IsInvocation) { @@ -50,7 +53,7 @@ namespace BTCPayServer.Rating return node; } } - public override SyntaxNode VisitIdentifierName(IdentifierNameSyntax node) + public override SyntaxNode? VisitIdentifierName(IdentifierNameSyntax node) { if (CurrencyPair.TryParse(node.Identifier.ValueText, out var currencyPair)) { @@ -122,11 +125,17 @@ namespace BTCPayServer.Rating // Remove every irrelevant statements this.root = ruleList.GetSyntaxNode(); } - public static bool TryParse(string str, out RateRules rules) + public static bool TryParse(string str, [MaybeNullWhen(false)] out RateRules rules) { return TryParse(str, out rules, out var unused); } - public static bool TryParse(string str, out RateRules rules, out List errors) + public static RateRules Parse(string str) + { + if (TryParse(str, out var rules, out var err)) + return rules; + throw new FormatException(String.Join(", ", err)); + } + public static bool TryParse(string str, [MaybeNullWhen(false)] out RateRules rules, [MaybeNullWhen(true)] out List errors) { str = ImplicitSatsRule + str; rules = null; @@ -194,6 +203,12 @@ namespace BTCPayServer.Rating return (ExpressionSyntax)CSharpSyntaxTree.ParseText(str, new CSharpParseOptions(LanguageVersion.Default).WithKind(SourceCodeKind.Script)).GetRoot().ChildNodes().First().ChildNodes().First().ChildNodes().First(); } + public static RateRules Combine(RateRules[] rateRules) + { + var str = string.Join(Environment.NewLine, rateRules.Select(r => r.ToString())); + return Parse(str); + } + public override string ToString() { return root.NormalizeWhitespace("", "\n") @@ -209,8 +224,8 @@ namespace BTCPayServer.Rating class ReplaceExchangeRateRewriter : CSharpSyntaxRewriter { public List Errors = new List(); - public ExchangeRates Rates; - public override SyntaxNode VisitInvocationExpression(InvocationExpressionSyntax node) + public ExchangeRates? Rates; + public override SyntaxNode? VisitInvocationExpression(InvocationExpressionSyntax node) { var exchangeName = node.Expression.ToString(); if (exchangeName.StartsWith("ERR_", StringComparison.OrdinalIgnoreCase)) @@ -227,7 +242,7 @@ namespace BTCPayServer.Rating } else { - var rate = Rates.GetRate(exchangeName, pair); + var rate = Rates?.GetRate(exchangeName, pair); if (rate == null) { Errors.Add(RateRulesErrors.RateUnavailable); @@ -349,7 +364,7 @@ namespace BTCPayServer.Rating } } - Stack _TupleValues = null; + Stack? _TupleValues = null; public override void VisitTupleExpression(TupleExpressionSyntax node) { _TupleValues = new Stack(); @@ -412,7 +427,7 @@ namespace BTCPayServer.Rating public ExchangeRates ExchangeRates = new ExchangeRates(); bool IsInvocation; - public override SyntaxNode VisitInvocationExpression(InvocationExpressionSyntax node) + public override SyntaxNode? VisitInvocationExpression(InvocationExpressionSyntax node) { if (IsInvocation) { @@ -427,7 +442,7 @@ namespace BTCPayServer.Rating } bool IsArgumentList; - public override SyntaxNode VisitArgumentList(ArgumentListSyntax node) + public override SyntaxNode? VisitArgumentList(ArgumentListSyntax node) { IsArgumentList = true; var result = base.VisitArgumentList(node); @@ -435,11 +450,11 @@ namespace BTCPayServer.Rating return result; } - string _ExchangeName = null; + string? _ExchangeName = null; public List Errors = new List(); const int MaxNestedCount = 8; - public override SyntaxNode VisitIdentifierName(IdentifierNameSyntax node) + public override SyntaxNode? VisitIdentifierName(IdentifierNameSyntax node) { if ( (!IsInvocation || IsArgumentList) && @@ -497,7 +512,7 @@ namespace BTCPayServer.Rating public static RateRule CreateFromExpression(string expression, CurrencyPair currencyPair) { var ex = RateRules.CreateExpression(expression); - RateRules.TryParse("", out var rules); + var rules = RateRules.Parse(""); return new RateRule(rules, currencyPair, ex); } public RateRule(RateRules parent, CurrencyPair currencyPair, SyntaxNode candidate) @@ -528,7 +543,7 @@ namespace BTCPayServer.Rating public bool Reevaluate() { - _BidAsk = null; + BidAsk = null; _EvaluatedNode = null; _Evaluated = null; Errors.Clear(); @@ -554,7 +569,7 @@ namespace BTCPayServer.Rating } return false; } - _BidAsk = calculate.Values.Pop(); + BidAsk = calculate.Values.Pop(); _EvaluatedNode = result; return true; } @@ -569,8 +584,8 @@ namespace BTCPayServer.Rating } } - SyntaxNode _EvaluatedNode; - string _Evaluated; + SyntaxNode? _EvaluatedNode; + string? _Evaluated; public bool HasError { get @@ -592,14 +607,6 @@ namespace BTCPayServer.Rating { return expression.NormalizeWhitespace("", "\n").ToString(); } - - BidAsk _BidAsk; - public BidAsk BidAsk - { - get - { - return _BidAsk; - } - } + public BidAsk? BidAsk { get; private set; } } } diff --git a/BTCPayServer/Data/StoreBlob.cs b/BTCPayServer/Data/StoreBlob.cs index 077e87f8a..9e539eee1 100644 --- a/BTCPayServer/Data/StoreBlob.cs +++ b/BTCPayServer/Data/StoreBlob.cs @@ -158,24 +158,9 @@ namespace BTCPayServer.Data public RateRules GetDefaultRateRules(IEnumerable defaultRates) { - var builder = new StringBuilder(); - foreach (var rates in defaultRates) - { - if (rates.Rates is { Length: > 0 } r) - { - foreach (var line in r) - { - builder.AppendLine(line); - } - builder.AppendLine("////////"); - builder.AppendLine(); - } - } - var preferredExchange = string.IsNullOrEmpty(PreferredExchange) ? GetRecommendedExchange() : PreferredExchange; - builder.AppendLine(CultureInfo.InvariantCulture, $"X_X = {preferredExchange}(X_X);"); - - RateRules.TryParse(builder.ToString(), out var rules); + var preferredExchangeRule = RateRules.Parse($"X_X = {preferredExchange}(X_X);"); + var rules = RateRules.Combine(defaultRates.Select(r => r.Rules).Concat([preferredExchangeRule]).ToArray()); rules.Spread = Spread; return rules; } diff --git a/BTCPayServer/DefaultRates.cs b/BTCPayServer/DefaultRates.cs index fb92b6c36..5210a94e8 100644 --- a/BTCPayServer/DefaultRates.cs +++ b/BTCPayServer/DefaultRates.cs @@ -1,2 +1,11 @@ +using System; +using System.Linq; +using BTCPayServer.Rating; + namespace BTCPayServer; -public record DefaultRates(string[] Rates); +public record DefaultRates(RateRules Rules) +{ + public DefaultRates(string[] Rules) : this(RateRules.Combine(Rules.Select(r => RateRules.Parse(r)).ToArray())) + { + } +}