001/** 002 * Copyright (c) 2025-2026, Michael Yang 杨福海 (fuhai999@gmail.com). 003 * <p> 004 * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * <p> 008 * http://www.gnu.org/licenses/lgpl-3.0.txt 009 * <p> 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package dev.tinyflow.core.chain; 017 018import dev.tinyflow.core.util.JsConditionUtil; 019import dev.tinyflow.core.util.StringUtil; 020import org.slf4j.Logger; 021 022import java.io.Serializable; 023import java.util.HashMap; 024import java.util.List; 025import java.util.Map; 026 027public abstract class Node implements Serializable { 028 private static final Logger log = org.slf4j.LoggerFactory.getLogger(Node.class); 029 030 protected String id; 031 protected String parentId; 032 protected String name; 033 protected String description; 034 035// protected List<Edge> inwardEdges; 036// protected List<Edge> outwardEdges; 037 038 protected NodeCondition condition; 039 protected NodeValidator validator; 040 041 // 循环执行相关属性 042 protected boolean loopEnable = false; // 是否启用循环执行 043 protected long loopIntervalMs = 3000; // 循环间隔时间(毫秒) 044 protected NodeCondition loopBreakCondition; // 跳出循环的条件 045 protected int maxLoopCount = 0; // 0 表示不限制循环次数 046 047 protected boolean retryEnable = false; 048 protected boolean resetRetryCountAfterNormal = false; 049 protected int maxRetryCount = 0; 050 protected long retryIntervalMs = 3000; 051 052 // 算力消耗定义,积分消耗 053 protected String computeCostExpr; 054 055 public String getId() { 056 return id; 057 } 058 059 public void setId(String id) { 060 this.id = id; 061 } 062 063 public String getParentId() { 064 return parentId; 065 } 066 067 public void setParentId(String parentId) { 068 this.parentId = parentId; 069 } 070 071 public String getName() { 072 return name; 073 } 074 075 public void setName(String name) { 076 this.name = name; 077 } 078 079 public String getDescription() { 080 return description; 081 } 082 083 public void setDescription(String description) { 084 this.description = description; 085 } 086 087// public List<Edge> getInwardEdges() { 088// return inwardEdges; 089// } 090// 091// public void setInwardEdges(List<Edge> inwardEdges) { 092// this.inwardEdges = inwardEdges; 093// } 094// 095// public List<Edge> getOutwardEdges() { 096//// return outwardEdges; 097// } 098// 099// public void setOutwardEdges(List<Edge> outwardEdges) { 100// this.outwardEdges = outwardEdges; 101// } 102 103 public NodeCondition getCondition() { 104 return condition; 105 } 106 107 public void setCondition(NodeCondition condition) { 108 this.condition = condition; 109 } 110 111 public NodeValidator getValidator() { 112 return validator; 113 } 114 115 public void setValidator(NodeValidator validator) { 116 this.validator = validator; 117 } 118 119// protected void addOutwardEdge(Edge edge) { 120// if (this.outwardEdges == null) { 121// this.outwardEdges = new ArrayList<>(); 122// } 123// this.outwardEdges.add(edge); 124// } 125// 126// protected void addInwardEdge(Edge edge) { 127// if (this.inwardEdges == null) { 128// this.inwardEdges = new ArrayList<>(); 129// } 130// this.inwardEdges.add(edge); 131// } 132 133 public boolean isLoopEnable() { 134 return loopEnable; 135 } 136 137 public void setLoopEnable(boolean loopEnable) { 138 this.loopEnable = loopEnable; 139 } 140 141 public long getLoopIntervalMs() { 142 return loopIntervalMs; 143 } 144 145 public void setLoopIntervalMs(long loopIntervalMs) { 146 this.loopIntervalMs = loopIntervalMs; 147 } 148 149 public NodeCondition getLoopBreakCondition() { 150 return loopBreakCondition; 151 } 152 153 public void setLoopBreakCondition(NodeCondition loopBreakCondition) { 154 this.loopBreakCondition = loopBreakCondition; 155 } 156 157 public int getMaxLoopCount() { 158 return maxLoopCount; 159 } 160 161 public void setMaxLoopCount(int maxLoopCount) { 162 this.maxLoopCount = maxLoopCount; 163 } 164 165 public List<Parameter> getParameters() { 166 return null; 167 } 168 169 public boolean isRetryEnable() { 170 return retryEnable; 171 } 172 173 public void setRetryEnable(boolean retryEnable) { 174 this.retryEnable = retryEnable; 175 } 176 177 public boolean isResetRetryCountAfterNormal() { 178 return resetRetryCountAfterNormal; 179 } 180 181 public void setResetRetryCountAfterNormal(boolean resetRetryCountAfterNormal) { 182 this.resetRetryCountAfterNormal = resetRetryCountAfterNormal; 183 } 184 185 public int getMaxRetryCount() { 186 return maxRetryCount; 187 } 188 189 public void setMaxRetryCount(int maxRetryCount) { 190 this.maxRetryCount = maxRetryCount; 191 } 192 193 public long getRetryIntervalMs() { 194 return retryIntervalMs; 195 } 196 197 public void setRetryIntervalMs(long retryIntervalMs) { 198 this.retryIntervalMs = retryIntervalMs; 199 } 200 201 public String getComputeCostExpr() { 202 return computeCostExpr; 203 } 204 205 public void setComputeCostExpr(String computeCostExpr) { 206 if (computeCostExpr != null) { 207 computeCostExpr = computeCostExpr.trim(); 208 } 209 this.computeCostExpr = computeCostExpr; 210 } 211 212 public NodeValidResult validate() throws Exception { 213 return validator != null ? validator.validate(this) : NodeValidResult.ok(); 214 } 215 216 217 public abstract Map<String, Object> execute(Chain chain); 218 219 public long calculateComputeCost(Chain chain, Map<String, Object> executeResult) { 220 221 if (StringUtil.noText(computeCostExpr)) { 222 return 0; 223 } 224 225 if (computeCostExpr.startsWith("{{") && computeCostExpr.endsWith("}}")) { 226 String expr = computeCostExpr.substring(2, computeCostExpr.length() - 2); 227 return doCalculateComputeCost(expr, chain, executeResult); 228 } else { 229 try { 230 return Long.parseLong(computeCostExpr); 231 } catch (NumberFormatException e) { 232 log.error(e.toString(), e); 233 } 234 return 0; 235 } 236 } 237 238 protected long doCalculateComputeCost(String expr, Chain chain, Map<String, Object> result) { 239// Map<String, Object> parameterValues = chain.getState().getParameterValuesOnly(this, this.getParameters(), null); 240 Map<String, Object> parameterValues = chain.getState().resolveParameters(this, this.getParameters(), null,true); 241 Map<String, Object> newMap = new HashMap<>(result); 242 newMap.putAll(parameterValues); 243 return JsConditionUtil.evalLong(expr, chain, newMap); 244 } 245}