328 lines
20 KiB
C#
328 lines
20 KiB
C#
using System.Globalization;
|
|
using NodePipeline.Abstractions;
|
|
using NodePipeline.Abstractions.Exceptions.Validation;
|
|
using NodePipeline.Abstractions.Interfaces;
|
|
using NodePipeline.Abstractions.Interfaces.Nodes;
|
|
using NodePipeline.Abstractions.Interfaces.Validation;
|
|
using NodePipeline.Abstractions.Models.Validation;
|
|
using NodePipeline.Abstractions.Validators;
|
|
using NodePipeline.Configuration.Abstractions.Models.Execute;
|
|
using NodePipeline.Engine.Abstractions;
|
|
using NodePipeline.Engine.NodeFields;
|
|
using NodePipeline.Engine.Utils;
|
|
using NodePipeline.Engine.Abstractions.Validation;
|
|
|
|
// ReSharper disable CheckNamespace
|
|
// ReSharper disable RedundantNameQualifier
|
|
// ReSharper disable UnusedParameter.Local
|
|
#nullable enable
|
|
|
|
namespace NodePipeline.Engine.Generated;
|
|
|
|
public sealed class GeneratedNodeValidator : IPipelineNodeValidator
|
|
{
|
|
private Dictionary<NodePortKey, NodePortInfo>? _allPorts;
|
|
public Dictionary<Type, INodeValidator> NodeValidators { get; set; } = [];
|
|
public Dictionary<Type, INodeFieldValidator> NodeFieldValidators { get; set; } = [];
|
|
public IPipelineLocalizationProvider PipelineLocalizationProvider { get; set; } = new PipelineLocalizationProvider();
|
|
|
|
public NodeValidationResult ValidateNode(string pipelineId, INodeFactory nodeFactory, NodeConfig nodeConfig, List<NodeConfig> allNodes, Dictionary<string, object?> parameters, CultureInfo cultureInfo)
|
|
{
|
|
var node = nodeFactory.CreateNode(pipelineId, nodeConfig);
|
|
nodeFactory.SetNodeParametersValues(pipelineId, node, nodeConfig.Id, parameters);
|
|
var nodeConnections = allNodes.SelectMany(q => q.Inputs
|
|
.Select(x => new KeyValuePair<string, InputSource>(GetNodeInputKey(q.Id, x.Key), x.Value))
|
|
).ToDictionary(q => q.Key, q => q.Value);
|
|
var ports = GetAllPorts(pipelineId, nodeFactory, allNodes);
|
|
switch (node)
|
|
{
|
|
case global::NodePipeline.Application.Nodes.FileImageSource2Node t1:
|
|
return Validate__NodePipeline_Application_Nodes_FileImageSource2Node__Node(pipelineId, nodeFactory, t1, nodeConfig.Id, nodeConnections, ports, cultureInfo);
|
|
case global::NodePipeline.Application.Nodes.FileImageSourceNode t2:
|
|
return Validate__NodePipeline_Application_Nodes_FileImageSourceNode__Node(pipelineId, nodeFactory, t2, nodeConfig.Id, nodeConnections, ports, cultureInfo);
|
|
case global::NodePipeline.Application.Nodes.GaussianBlurNode t3:
|
|
return Validate__NodePipeline_Application_Nodes_GaussianBlurNode__Node(pipelineId, nodeFactory, t3, nodeConfig.Id, nodeConnections, ports, cultureInfo);
|
|
case global::NodePipeline.Application.Nodes.MaskApplyNode t4:
|
|
return Validate__NodePipeline_Application_Nodes_MaskApplyNode__Node(pipelineId, nodeFactory, t4, nodeConfig.Id, nodeConnections, ports, cultureInfo);
|
|
case global::NodePipeline.Application.Nodes.SaveImage2Node t5:
|
|
return Validate__NodePipeline_Application_Nodes_SaveImage2Node__Node(pipelineId, nodeFactory, t5, nodeConfig.Id, nodeConnections, ports, cultureInfo);
|
|
case global::NodePipeline.Application.Nodes.SaveImageNode t6:
|
|
return Validate__NodePipeline_Application_Nodes_SaveImageNode__Node(pipelineId, nodeFactory, t6, nodeConfig.Id, nodeConnections, ports, cultureInfo);
|
|
default:
|
|
throw new UnknownNodeTypeException(nodeConfig.Type, nodeConfig.Id);
|
|
}
|
|
}
|
|
|
|
private NodeValidationResult Validate__NodePipeline_Application_Nodes_FileImageSource2Node__Node(string pipelineId, INodeFactory nodeFactory, global::NodePipeline.Application.Nodes.FileImageSource2Node node, string nodeId, IReadOnlyDictionary<string, InputSource> nodePortConnections, IReadOnlyDictionary<NodePortKey, NodePortInfo> ports, CultureInfo cultureInfo)
|
|
{
|
|
var fieldResults = new Dictionary<string, List<NodeFieldValidationResult>>();
|
|
|
|
var portsValidationResult = ValidateNodePorts(pipelineId, nodeFactory, NodeNamePrefixSettings.TrimNodeName("NodePipeline.Application.Nodes.FileImageSource2"), nodeId, nodePortConnections, ports, out var portResults, cultureInfo);
|
|
var isValid = portsValidationResult != ValidationResult.HasErrors;
|
|
return !isValid
|
|
? GetErrorValidationResult(ValidationResult.HasErrors, nodeId, fieldResults, portResults, cultureInfo)
|
|
: SuccessNodeValidationResult(portsValidationResult == ValidationResult.HasWarnings, fieldResults, portResults);
|
|
}
|
|
|
|
private NodeValidationResult Validate__NodePipeline_Application_Nodes_FileImageSourceNode__Node(string pipelineId, INodeFactory nodeFactory, global::NodePipeline.Application.Nodes.FileImageSourceNode node, string nodeId, IReadOnlyDictionary<string, InputSource> nodePortConnections, IReadOnlyDictionary<NodePortKey, NodePortInfo> ports, CultureInfo cultureInfo)
|
|
{
|
|
var validationResult = ValidationResult.Valid;
|
|
var fieldResults = new Dictionary<string, List<NodeFieldValidationResult>>
|
|
{
|
|
{ "FileName", [] },
|
|
{ "Extension", [] },
|
|
{ "Directory", [] },
|
|
};
|
|
|
|
var r2 = new StringLengthValidator(PipelineLocalizationProvider, 1, null).Validate(node.FileName);
|
|
fieldResults["FileName"].Add(r2);
|
|
UpdateValidationResult(r2.Result, ref validationResult);
|
|
|
|
var r3 = CheckRequiredNodeParameter<string>(nodeId, node.FileName, "FileName", cultureInfo);
|
|
fieldResults["FileName"].Add(r3);
|
|
UpdateValidationResult(r3.Result, ref validationResult);
|
|
|
|
var r4 = new StringLengthValidator(PipelineLocalizationProvider, 1, 10).Validate(node.Extension);
|
|
fieldResults["Extension"].Add(r4);
|
|
UpdateValidationResult(r4.Result, ref validationResult);
|
|
|
|
var r5 = CheckRequiredNodeParameter<string>(nodeId, node.Extension, "Extension", cultureInfo);
|
|
fieldResults["Extension"].Add(r5);
|
|
UpdateValidationResult(r5.Result, ref validationResult);
|
|
|
|
var r6 = new StringLengthValidator(PipelineLocalizationProvider, 1, null).Validate(node.Directory);
|
|
fieldResults["Directory"].Add(r6);
|
|
UpdateValidationResult(r6.Result, ref validationResult);
|
|
|
|
var r7 = CheckRequiredNodeParameter<string>(nodeId, node.Directory, "Directory", cultureInfo);
|
|
fieldResults["Directory"].Add(r7);
|
|
UpdateValidationResult(r7.Result, ref validationResult);
|
|
|
|
|
|
var portsValidationResult = ValidateNodePorts(pipelineId, nodeFactory, NodeNamePrefixSettings.TrimNodeName("NodePipeline.Application.Nodes.FileImageSource"), nodeId, nodePortConnections, ports, out var portResults, cultureInfo);
|
|
var isValid = validationResult != ValidationResult.HasErrors && portsValidationResult != ValidationResult.HasErrors;
|
|
UpdateValidationResult(portsValidationResult, ref validationResult);
|
|
return !isValid
|
|
? GetErrorValidationResult(validationResult, nodeId, fieldResults, portResults, cultureInfo)
|
|
: GetNodeValidator(typeof(global::NodePipeline.Application.FileImageSourceNodeValidator)).Validate(
|
|
new Dictionary<string, object>
|
|
{
|
|
{ "FileName", node.FileName.Value },
|
|
{ "Extension", node.Extension.Value },
|
|
{ "Directory", node.Directory.Value },
|
|
}, fieldResults, portResults);
|
|
}
|
|
|
|
private NodeValidationResult Validate__NodePipeline_Application_Nodes_GaussianBlurNode__Node(string pipelineId, INodeFactory nodeFactory, global::NodePipeline.Application.Nodes.GaussianBlurNode node, string nodeId, IReadOnlyDictionary<string, InputSource> nodePortConnections, IReadOnlyDictionary<NodePortKey, NodePortInfo> ports, CultureInfo cultureInfo)
|
|
{
|
|
var validationResult = ValidationResult.Valid;
|
|
var fieldResults = new Dictionary<string, List<NodeFieldValidationResult>>
|
|
{
|
|
{ "Radius", [] },
|
|
};
|
|
|
|
var r2 = new NumberRangeValidator<int>(PipelineLocalizationProvider, 0, 300).Validate(node.Radius);
|
|
fieldResults["Radius"].Add(r2);
|
|
UpdateValidationResult(r2.Result, ref validationResult);
|
|
|
|
|
|
var portsValidationResult = ValidateNodePorts(pipelineId, nodeFactory, NodeNamePrefixSettings.TrimNodeName("NodePipeline.Application.Nodes.GaussianBlur"), nodeId, nodePortConnections, ports, out var portResults, cultureInfo);
|
|
var isValid = validationResult != ValidationResult.HasErrors && portsValidationResult != ValidationResult.HasErrors;
|
|
UpdateValidationResult(portsValidationResult, ref validationResult);
|
|
return !isValid
|
|
? GetErrorValidationResult(validationResult, nodeId, fieldResults, portResults, cultureInfo)
|
|
: SuccessNodeValidationResult(validationResult == ValidationResult.HasWarnings || portsValidationResult == ValidationResult.HasWarnings, fieldResults, portResults);
|
|
}
|
|
|
|
private NodeValidationResult Validate__NodePipeline_Application_Nodes_MaskApplyNode__Node(string pipelineId, INodeFactory nodeFactory, global::NodePipeline.Application.Nodes.MaskApplyNode node, string nodeId, IReadOnlyDictionary<string, InputSource> nodePortConnections, IReadOnlyDictionary<NodePortKey, NodePortInfo> ports, CultureInfo cultureInfo)
|
|
{
|
|
var fieldResults = new Dictionary<string, List<NodeFieldValidationResult>>
|
|
{
|
|
{ "Mode", [] },
|
|
};
|
|
|
|
var portsValidationResult = ValidateNodePorts(pipelineId, nodeFactory, NodeNamePrefixSettings.TrimNodeName("NodePipeline.Application.Nodes.MaskApply"), nodeId, nodePortConnections, ports, out var portResults, cultureInfo);
|
|
var isValid = portsValidationResult != ValidationResult.HasErrors;
|
|
return !isValid
|
|
? GetErrorValidationResult(ValidationResult.HasErrors, nodeId, fieldResults, portResults, cultureInfo)
|
|
: SuccessNodeValidationResult(portsValidationResult == ValidationResult.HasWarnings, fieldResults, portResults);
|
|
}
|
|
|
|
private NodeValidationResult Validate__NodePipeline_Application_Nodes_SaveImage2Node__Node(string pipelineId, INodeFactory nodeFactory, global::NodePipeline.Application.Nodes.SaveImage2Node node, string nodeId, IReadOnlyDictionary<string, InputSource> nodePortConnections, IReadOnlyDictionary<NodePortKey, NodePortInfo> ports, CultureInfo cultureInfo)
|
|
{
|
|
var fieldResults = new Dictionary<string, List<NodeFieldValidationResult>>();
|
|
|
|
var portsValidationResult = ValidateNodePorts(pipelineId, nodeFactory, NodeNamePrefixSettings.TrimNodeName("NodePipeline.Application.Nodes.SaveImage2"), nodeId, nodePortConnections, ports, out var portResults, cultureInfo);
|
|
var isValid = portsValidationResult != ValidationResult.HasErrors;
|
|
return !isValid
|
|
? GetErrorValidationResult(ValidationResult.HasErrors, nodeId, fieldResults, portResults, cultureInfo)
|
|
: SuccessNodeValidationResult(portsValidationResult == ValidationResult.HasWarnings, fieldResults, portResults);
|
|
}
|
|
|
|
private NodeValidationResult Validate__NodePipeline_Application_Nodes_SaveImageNode__Node(string pipelineId, INodeFactory nodeFactory, global::NodePipeline.Application.Nodes.SaveImageNode node, string nodeId, IReadOnlyDictionary<string, InputSource> nodePortConnections, IReadOnlyDictionary<NodePortKey, NodePortInfo> ports, CultureInfo cultureInfo)
|
|
{
|
|
var validationResult = ValidationResult.Valid;
|
|
var fieldResults = new Dictionary<string, List<NodeFieldValidationResult>>
|
|
{
|
|
{ "FileName", [] },
|
|
{ "Extension", [] },
|
|
{ "Directory", [] },
|
|
};
|
|
|
|
var r2 = CheckRequiredNodeParameter<string>(nodeId, node.FileName, "FileName", cultureInfo);
|
|
fieldResults["FileName"].Add(r2);
|
|
UpdateValidationResult(r2.Result, ref validationResult);
|
|
|
|
var r3 = CheckRequiredNodeParameter<string>(nodeId, node.Extension, "Extension", cultureInfo);
|
|
fieldResults["Extension"].Add(r3);
|
|
UpdateValidationResult(r3.Result, ref validationResult);
|
|
|
|
var r4 = GetNodeFieldValidator<string>(typeof(global::NodePipeline.Application.ExtensionValidator)).Validate(node.Extension);
|
|
fieldResults["Extension"].Add(r4);
|
|
UpdateValidationResult(r4.Result, ref validationResult);
|
|
|
|
var r5 = CheckRequiredNodeParameter<string>(nodeId, node.Directory, "Directory", cultureInfo);
|
|
fieldResults["Directory"].Add(r5);
|
|
UpdateValidationResult(r5.Result, ref validationResult);
|
|
|
|
|
|
var portsValidationResult = ValidateNodePorts(pipelineId, nodeFactory, "FileImageDestination", nodeId, nodePortConnections, ports, out var portResults, cultureInfo);
|
|
var isValid = validationResult != ValidationResult.HasErrors && portsValidationResult != ValidationResult.HasErrors;
|
|
UpdateValidationResult(portsValidationResult, ref validationResult);
|
|
return !isValid
|
|
? GetErrorValidationResult(validationResult, nodeId, fieldResults, portResults, cultureInfo)
|
|
: SuccessNodeValidationResult(validationResult == ValidationResult.HasWarnings || portsValidationResult == ValidationResult.HasWarnings, fieldResults, portResults);
|
|
}
|
|
|
|
|
|
private IReadOnlyDictionary<NodePortKey, NodePortInfo> GetAllPorts(string pipelineId, INodeFactory nodeFactory, List<NodeConfig> allNodes)
|
|
{
|
|
var nodeTypes = allNodes.Select(q => q.Type)
|
|
.Distinct()
|
|
.ToHashSet();
|
|
|
|
var nodeList = allNodes
|
|
.GroupBy(q => q.Type,
|
|
(type, g) => new { Type = type, NodeIds = g.Select(q => q.Id) })
|
|
.ToDictionary(q => q.Type, q => q.NodeIds);
|
|
_allPorts ??= nodeFactory.GetAllPorts(pipelineId, nodeTypes, nodeList);
|
|
return _allPorts.AsReadOnly();
|
|
}
|
|
|
|
private INodeFieldValidator<T> GetNodeFieldValidator<T>(Type validatorType)
|
|
{
|
|
if (!NodeFieldValidators.TryGetValue(validatorType, out var validator)
|
|
|| validator is not INodeFieldValidator<T> genericValidator)
|
|
throw new UserDefinedNodeFieldValidatorNotFoundException(validatorType.FullName ?? validatorType.Name);
|
|
return genericValidator;
|
|
}
|
|
|
|
private ValidationResult ValidateNodePorts(string pipelineId, INodeFactory nodeFactory, string nodeType, string nodeId,
|
|
IReadOnlyDictionary<string, InputSource> nodePortConnections, IReadOnlyDictionary<NodePortKey, NodePortInfo> ports,
|
|
out Dictionary<string, List<NodeFieldValidationResult>> inputPortValidationResults, CultureInfo cultureInfo)
|
|
{
|
|
var result = ValidationResult.Valid;
|
|
inputPortValidationResults = new Dictionary<string, List<NodeFieldValidationResult>>();
|
|
|
|
var inputPorts = nodeFactory.GetNodeInputPorts(pipelineId, nodeType, nodeId);
|
|
foreach (var inputPort in inputPorts)
|
|
{
|
|
var code = NodeFieldCodeGenerator.GenerateFieldCode(nodeId, inputPort.Name,
|
|
inputPort.Input ? FieldDirection.Input : FieldDirection.Output);
|
|
inputPortValidationResults[code] = [];
|
|
var hasConnection = nodePortConnections.TryGetValue(GetNodeInputKey(nodeId, inputPort.Name), out var connection);
|
|
if (inputPort.Required && !hasConnection)
|
|
{
|
|
inputPortValidationResults[code].Add(new NodeFieldValidationResult(ValidationResult.HasErrors,
|
|
PipelineLocalizationProvider.GetLocalizedString(Constants.ValidationResults.ErrorMessages.RequiredInputPortHasNoConnectionError, cultureInfo, inputPort.Name, nodeId)));
|
|
UpdateValidationResult(ValidationResult.HasErrors, ref result);
|
|
continue;
|
|
}
|
|
if (!hasConnection || connection == null) continue;
|
|
|
|
var portValidationResult = ValidateInputPort(nodeId, inputPort, connection, ports, cultureInfo);
|
|
inputPortValidationResults[code].Add(portValidationResult);
|
|
UpdateValidationResult(portValidationResult.Result, ref result);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
private NodeFieldValidationResult ValidateInputPort(string nodeId, NodePortInfo inputPort, InputSource connection,
|
|
IReadOnlyDictionary<NodePortKey, NodePortInfo> ports, CultureInfo cultureInfo)
|
|
{
|
|
if (!ports.TryGetValue(new NodePortKey(connection.NodeId, connection.OutputName, false), out var outputPort))
|
|
{
|
|
return new NodeFieldValidationResult(ValidationResult.HasErrors, PipelineLocalizationProvider
|
|
.GetLocalizedString(Constants.ValidationResults.ErrorMessages.OutputPortNotFoundError, cultureInfo, connection.OutputName,
|
|
connection.NodeId, inputPort.Name, nodeId));
|
|
}
|
|
|
|
if (inputPort.Type != outputPort.Type)
|
|
{
|
|
return new NodeFieldValidationResult(ValidationResult.HasErrors, PipelineLocalizationProvider
|
|
.GetLocalizedString(Constants.ValidationResults.ErrorMessages.PortsTypeMismatchError, cultureInfo,
|
|
inputPort.Name, nodeId, inputPort.Type, connection.OutputName, connection.NodeId, outputPort.Type));
|
|
}
|
|
|
|
if (inputPort.IsNullable == outputPort.IsNullable)
|
|
{
|
|
return SuccessNodeFieldValidationResult();
|
|
}
|
|
|
|
if (!inputPort.IsNullable && outputPort.IsNullable)
|
|
{
|
|
return new NodeFieldValidationResult(
|
|
ValidationResult.HasWarnings, PipelineLocalizationProvider
|
|
.GetLocalizedString(Constants.ValidationResults.ErrorMessages.NullableAndNonNullablePortsConnectionWarning, cultureInfo,
|
|
inputPort.Name, nodeId, inputPort.Type, connection.OutputName, connection.NodeId, outputPort.Type));
|
|
}
|
|
|
|
return SuccessNodeFieldValidationResult();
|
|
}
|
|
|
|
private static string GetNodeInputKey(string nodeId, string inputPortName)
|
|
{
|
|
return string.Concat(nodeId, "_", inputPortName);
|
|
}
|
|
|
|
private INodeValidator GetNodeValidator(Type validatorType)
|
|
{
|
|
if (!NodeValidators.TryGetValue(validatorType, out var validator))
|
|
throw new UserDefinedNodeValidatorNotFoundException(validatorType.FullName ?? validatorType.Name);
|
|
return validator;
|
|
}
|
|
|
|
private NodeFieldValidationResult CheckRequiredNodeParameter<T>(string nodeId, NodePipeline.Abstractions.Models.NodeField<T> nodeField, string nodeParameterName, CultureInfo cultureInfo)
|
|
{
|
|
return nodeField.Value is not null
|
|
? new NodeFieldValidationResult(ValidationResult.Valid, null)
|
|
: new NodeFieldValidationResult(ValidationResult.HasErrors, PipelineLocalizationProvider
|
|
.GetLocalizedString(Constants.ValidationResults.ErrorMessages.RequiredNodeParameterValidationError, cultureInfo, nodeParameterName, nodeId));
|
|
}
|
|
|
|
private static NodeValidationResult SuccessNodeValidationResult(bool hasWarnings, Dictionary<string, List<NodeFieldValidationResult>> fieldResults, Dictionary<string, List<NodeFieldValidationResult>> portResults) =>
|
|
new(hasWarnings ? ValidationResult.HasWarnings : ValidationResult.Valid, string.Empty,
|
|
fieldResults.AsReadOnly(), portResults.AsReadOnly());
|
|
|
|
private NodeValidationResult GetErrorValidationResult(ValidationResult validationResult, string nodeId, Dictionary<string, List<NodeFieldValidationResult>> fieldResults, Dictionary<string, List<NodeFieldValidationResult>> portResults, CultureInfo cultureInfo) =>
|
|
new(validationResult, PipelineLocalizationProvider.GetLocalizedString(Constants.ValidationResults.ErrorMessages.NodeValidationError, cultureInfo, nodeId), fieldResults.AsReadOnly(), portResults.AsReadOnly());
|
|
|
|
private static NodeFieldValidationResult SuccessNodeFieldValidationResult() =>
|
|
new NodeFieldValidationResult(ValidationResult.Valid, null);
|
|
|
|
private static void UpdateValidationResult(ValidationResult validationResult, ref ValidationResult parametersValidationResult)
|
|
{
|
|
if (validationResult == parametersValidationResult || validationResult == ValidationResult.Valid) return;
|
|
|
|
parametersValidationResult = validationResult switch
|
|
{
|
|
ValidationResult.HasWarnings when parametersValidationResult == ValidationResult.Valid => ValidationResult.HasWarnings,
|
|
ValidationResult.HasErrors when parametersValidationResult != ValidationResult.HasErrors => ValidationResult.HasErrors,
|
|
_ => parametersValidationResult
|
|
};
|
|
}
|
|
|
|
}
|
|
#nullable restore
|