69 lines
2.6 KiB
C#
69 lines
2.6 KiB
C#
using System.Text.Json.Nodes;
|
|
using w4c_workflows.Models.Nodes;
|
|
|
|
namespace w4c_workflows.Services.Nodes.Executors;
|
|
|
|
/// <summary>
|
|
/// Switch node. Evaluates an ordered rule list per item and routes the item to
|
|
/// the first matching rule's output port (port 0..3). Unmatched items go to the
|
|
/// fallback port (4) unless <c>fallbackEnabled</c> is false. Rules beyond the
|
|
/// blueprint's four rule ports are ignored.
|
|
/// </summary>
|
|
public sealed class SwitchNodeExecutor : INodeExecutor
|
|
{
|
|
/// <summary>Number of rule output ports on the blueprint (fallback is the next one).</summary>
|
|
public const int RulePorts = 4;
|
|
|
|
private const int FallbackPort = RulePorts;
|
|
|
|
public string Type => "core.switch";
|
|
|
|
public Task<NodeExecutionOutcome> RunAsync(NodeExecutionContext context, CancellationToken ct)
|
|
{
|
|
var item = context.Input(0).FirstOrDefault();
|
|
if (item == null)
|
|
return Task.FromResult(NodeExecutionOutcome.Empty);
|
|
|
|
var ports = new List<IReadOnlyList<FlowItem>>(RulePorts + 1);
|
|
for (var i = 0; i <= RulePorts; i++)
|
|
ports.Add(Array.Empty<FlowItem>());
|
|
|
|
var rules = context.Parameters["rules"] as JsonArray ?? new JsonArray();
|
|
for (var i = 0; i < rules.Count && i < RulePorts; i++)
|
|
{
|
|
if (rules[i] is not JsonObject rule)
|
|
continue;
|
|
|
|
var op = rule["operator"] is JsonValue value && value.TryGetValue<string>(out var text)
|
|
? text
|
|
: NodeConditionEvaluator.DefaultOperator;
|
|
var caseSensitive = rule["caseSensitive"] is JsonValue flag
|
|
&& flag.TryGetValue<bool>(out var cs) && cs;
|
|
|
|
bool matched;
|
|
try
|
|
{
|
|
matched = NodeConditionEvaluator.Evaluate(rule["left"], op, rule["right"], caseSensitive);
|
|
}
|
|
catch (ArgumentException ex)
|
|
{
|
|
return Task.FromResult(NodeExecutionOutcome.Failed(ex.Message, "invalid_condition"));
|
|
}
|
|
|
|
if (!matched)
|
|
continue;
|
|
|
|
ports[i] = new List<FlowItem> { item };
|
|
return Task.FromResult(new NodeExecutionOutcome { Outputs = ports });
|
|
}
|
|
|
|
if (ReadBool(context, "fallbackEnabled", defaultValue: true))
|
|
ports[FallbackPort] = new List<FlowItem> { item };
|
|
|
|
return Task.FromResult(new NodeExecutionOutcome { Outputs = ports });
|
|
}
|
|
|
|
private static bool ReadBool(NodeExecutionContext context, string name, bool defaultValue)
|
|
=> context.Parameters[name] is JsonValue value && value.TryGetValue<bool>(out var flag) ? flag : defaultValue;
|
|
}
|