//----------------------------------------------------------------------- //----------------------------------------------------------------------- // file="BlueprintNode.cs" // Project: StgSharp // AuthorGroup: Nitload Space // Copyright (c) Nitload Space. All rights reserved. // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation // files (the “Software”), to deal in the Software without restriction, // including without limitation the rights to use, copy, modify, merge, // publish, distribute, sublicense, and/or sell copies of the Software, // and to permit persons to whom the Software is furnished to do so, // subject to the following conditions: // // The above copyright notice and // this permission notice shall be included in all copies // or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED “AS IS”, // WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, // ARISING FROM, OUT OF OR IN CONNECTION WITH // THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // //----------------------------------------------------------------------- //----------------------------------------------------------------------- using StgSharp.Entities; using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; using System.Text; using System.Threading; using System.Threading.Tasks; namespace StgSharp.Logic { public delegate void BlueprintNodeAction( in Dictionary inpput, in Dictionary output); /// /// /// /// /// Reset pipeline has risk, this operation is a direct operation to port /// in current node, the port on the other node cannot get the change. /// #pragma warning disable CA1036 public class BlueprintNode : IComparable #pragma warning restore CA1036 { private BlueprintNodeAction mainOperation; private protected bool levelAvailable, nativeRequested; private protected int _level; private string name; private protected Dictionary _inputInterfaces; private protected Dictionary _outputInterfaces; internal BlueprintNode(string name, BlueprintNodeAction operation, bool isNative, string[] inputPorts, string[] outputPorts) { this.levelAvailable = false; this.name = name; nativeRequested = isNative; mainOperation = operation; _inputInterfaces = new Dictionary(); _outputInterfaces = new Dictionary(); if (inputPorts.Length == 0 ) { throw new ArgumentNullException(nameof(inputPorts)); } if (outputPorts.Length == 0) { throw new ArgumentNullException(nameof(outputPorts)); } foreach (var portName in inputPorts) { _inputInterfaces.Add(portName, null); } foreach (var portName in outputPorts) { _outputInterfaces.Add(portName, null); } } public BlueprintNode(string name, IConvertableToBlueprintNode convertable) { this.levelAvailable = false; this.name = name; _inputInterfaces = new Dictionary(); _outputInterfaces = new Dictionary(); mainOperation = convertable.MainExecution; foreach (var soket in convertable.InputInterfacesName) { _inputInterfaces.Add(soket, null); } foreach (var soket in convertable.OutputInterfacesName) { _outputInterfaces.Add(soket, null); } } public BlueprintNode(string name, string[] inputPorts, string[] outputPorts ) { this.levelAvailable = false; this.name = name; _inputInterfaces = new Dictionary(); _outputInterfaces = new Dictionary(); if (inputPorts.Length * outputPorts.Length == 0) { throw new Exception(); } foreach (var portName in inputPorts) { _inputInterfaces.Add(portName, null); } foreach (var portName in outputPorts) { _outputInterfaces.Add(portName, null); } } public bool IsNative { get => nativeRequested; internal set => nativeRequested = value; } public int Level { get { if (levelAvailable) { return _level; } _level = 0; foreach (var item in _inputInterfaces) { if (item.Value == null) { continue; } if (_level <= item.Value.Level) { _level = item.Value.Level; } } _level += 1; return _level; } } public string Name => name; internal Dictionary InputInterfaces => _inputInterfaces; internal Dictionary OutputInterfaces => _outputInterfaces; public void AddAfter( BlueprintNode former, string formerOutputPortName, string thisInputPortName) { this.levelAvailable = false; BlueprintPipeline pipeline = new BlueprintPipeline(former, this); if (former is BeginningNode bnode) { bnode.SetCertainOutputPort(formerOutputPortName, pipeline); } else { former.SetCertainOutputPort(formerOutputPortName, pipeline); } SetCertainInputPort(thisInputPortName, pipeline); } public void AddBefore( BlueprintNode after, string thisOutputPortName, string afterInputPortName) { this.levelAvailable = false; BlueprintPipeline pipeline = new BlueprintPipeline(this, after); if (after is EndingNode enode) { enode.SetCertainInputPort(afterInputPortName, pipeline); } else { after.SetCertainInputPort(afterInputPortName, pipeline); } SetCertainOutputPort(thisOutputPortName, pipeline); } public void Run() { try { //Console.WriteLine(name); BlueprintPipeline.WaitAll(_inputInterfaces); mainOperation(in _inputInterfaces, in _outputInterfaces); } catch (Exception) { throw; } } public int CompareTo(BlueprintNode other) { #pragma warning disable CA1062 return this.Level.CompareTo(other.Level); #pragma warning restore CA1062 } #region port operation public BlueprintPipeline GetCertainInputPort(string name) { BlueprintPipeline ret; if (!_inputInterfaces.TryGetValue(name,out ret)) { throw new Exception($"Cannot find the interface named {name} in node {Name}."); } return ret; } public BlueprintPipeline GetCertainOutputPort(string name) { BlueprintPipeline ret; if (!_outputInterfaces.TryGetValue(name, out ret)) { throw new Exception($"Cannot find the interface named {name} in node {Name}."); } return ret; } public void SetCertainInputPort(string name, BlueprintPipeline pipeline) { if (!_inputInterfaces.ContainsKey(name)) { throw new Exception($"Cannot find the interface named {name} in node {Name}."); } _inputInterfaces[name] = pipeline; } public void SetCertainOutputPort(string name, BlueprintPipeline pipeline) { if (!_outputInterfaces.ContainsKey(name)) { throw new Exception($"Cannot find the interface named {name} in node {Name}."); } _outputInterfaces[name] = pipeline; } #endregion }//--------------------------------- end of class ----------------------------------- public interface IConvertableToBlueprintNode { public string[] InputInterfacesName { get; } public BlueprintNodeAction MainExecution { get; } public string[] OutputInterfacesName { get; } } public class BlueprintNodeRunException : Exception { public BlueprintNodeRunException() { } public BlueprintNodeRunException(Exception ex) : base(string.Empty, ex) { } public BlueprintNodeRunException(string message) : base(message) { } public BlueprintNodeRunException(string message, Exception innerException) : base(message, innerException) { } protected BlueprintNodeRunException(SerializationInfo info, StreamingContext context) : base(info, context) { } } }