mirror of
https://gitee.com/ThingsGateway/ThingsGateway.git
synced 2025-10-25 20:53:10 +08:00
feat: 规则引擎 自定义执行脚本支持 `IDisposable` 接口
refactor: 脚本内日志对象统一命名为 ``Logger``
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
<Project>
|
||||
|
||||
<PropertyGroup>
|
||||
<PluginVersion>10.2.3</PluginVersion>
|
||||
<ProPluginVersion>10.2.3</ProPluginVersion>
|
||||
<PluginVersion>10.2.4</PluginVersion>
|
||||
<ProPluginVersion>10.2.4</ProPluginVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
|
||||
@@ -70,6 +70,10 @@ public static class CSharpScriptEngineExtension
|
||||
}
|
||||
}
|
||||
|
||||
public static void Remove(string source)
|
||||
{
|
||||
Instance.Remove($"{CacheKey}-{source}");
|
||||
}
|
||||
|
||||
private static MemoryCache Instance { get; set; } = new MemoryCache();
|
||||
|
||||
|
||||
@@ -8,5 +8,5 @@ public abstract class TextNode : PlaceholderModel
|
||||
}
|
||||
|
||||
[ModelValue]
|
||||
public string Text { get; set; }
|
||||
public virtual string Text { get; set; }
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
|
||||
using ThingsGateway.Gateway.Application;
|
||||
using ThingsGateway.NewLife;
|
||||
|
||||
using TouchSocket.Core;
|
||||
|
||||
@@ -10,11 +11,40 @@ public class ExecuteScriptNode : TextNode, IActuatorNode, IExexcuteExpressionsBa
|
||||
{
|
||||
public ExecuteScriptNode(string id, Point? position = null) : base(id, position) { Title = "ExecuteScriptNode"; Placeholder = "ExecuteScriptNode.Placeholder"; }
|
||||
|
||||
private string text;
|
||||
|
||||
[ModelValue]
|
||||
public override string Text
|
||||
{
|
||||
get
|
||||
{
|
||||
return text;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (text != value)
|
||||
{
|
||||
try
|
||||
{
|
||||
var exexcuteExpressions = CSharpScriptEngineExtension.Do<IExexcuteExpressions>(text);
|
||||
exexcuteExpressions.TryDispose();
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
}
|
||||
CSharpScriptEngineExtension.Remove(text);
|
||||
}
|
||||
|
||||
text = value;
|
||||
}
|
||||
}
|
||||
|
||||
Task<NodeOutput> IActuatorNode.ExecuteAsync(NodeInput input, CancellationToken cancellationToken)
|
||||
{
|
||||
LogMessage?.Trace($"Execute script");
|
||||
Logger?.Trace($"Execute script");
|
||||
var exexcuteExpressions = CSharpScriptEngineExtension.Do<IExexcuteExpressions>(Text);
|
||||
exexcuteExpressions.Logger = LogMessage;
|
||||
exexcuteExpressions.Logger = Logger;
|
||||
return exexcuteExpressions.ExecuteAsync(input, cancellationToken);
|
||||
|
||||
}
|
||||
|
||||
@@ -19,13 +19,13 @@ public class VariableRpcNode : VariableNode, IActuatorNode
|
||||
{
|
||||
var data = await value.RpcAsync(input.JToken.ToString(), $"RulesEngine: {RulesEngineName}", cancellationToken).ConfigureAwait(false);
|
||||
if (data.IsSuccess)
|
||||
LogMessage?.Trace($" VariableRpcNode - VariableName {Text} : execute success");
|
||||
Logger?.Trace($" VariableRpcNode - VariableName {Text} : execute success");
|
||||
else
|
||||
LogMessage?.Warning($" VariableRpcNode - VariableName {Text} : {data.ErrorMessage}");
|
||||
Logger?.Warning($" VariableRpcNode - VariableName {Text} : {data.ErrorMessage}");
|
||||
return new NodeOutput() { Value = data };
|
||||
}
|
||||
}
|
||||
LogMessage?.Warning($" VariableRpcNode - VariableName {Text} : not found");
|
||||
Logger?.Warning($" VariableRpcNode - VariableName {Text} : not found");
|
||||
return new NodeOutput() { };
|
||||
}
|
||||
|
||||
|
||||
@@ -11,5 +11,5 @@ public abstract class BaseNode : NodeModel, INode
|
||||
}
|
||||
|
||||
public string RulesEngineName { get; set; }
|
||||
public ILog LogMessage { get; set; }
|
||||
public ILog Logger { get; set; }
|
||||
}
|
||||
|
||||
@@ -15,9 +15,9 @@ public class ConditionNode : TextNode, IConditionNode
|
||||
|
||||
Task<bool> IConditionNode.ExecuteAsync(NodeInput input, CancellationToken cancellationToken)
|
||||
{
|
||||
var value = Text.GetExpressionsResult(input.Value, LogMessage);
|
||||
var value = Text.GetExpressionsResult(input.Value, Logger);
|
||||
var next = value.ToBoolean(false);
|
||||
LogMessage?.Trace($"Condition result: {next}");
|
||||
Logger?.Trace($"Condition result: {next}");
|
||||
return Task.FromResult(next);
|
||||
}
|
||||
|
||||
|
||||
@@ -12,10 +12,10 @@ public class DataNode : TextNode, IExpressionNode
|
||||
|
||||
Task<NodeOutput> IExpressionNode.ExecuteAsync(NodeInput input, CancellationToken cancellationToken)
|
||||
{
|
||||
var value = Text.GetExpressionsResult(input.Value, LogMessage);
|
||||
var value = Text.GetExpressionsResult(input.Value, Logger);
|
||||
NodeOutput nodeOutput = new();
|
||||
nodeOutput.Value = value;
|
||||
LogMessage?.Trace($"Data result: {nodeOutput.JToken?.ToString(Newtonsoft.Json.Formatting.Indented)}");
|
||||
Logger?.Trace($"Data result: {nodeOutput.JToken?.ToString(Newtonsoft.Json.Formatting.Indented)}");
|
||||
return Task.FromResult(nodeOutput);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ public class DelayNode : NumberNode, IExpressionNode
|
||||
|
||||
async Task<NodeOutput> IExpressionNode.ExecuteAsync(NodeInput input, CancellationToken cancellationToken)
|
||||
{
|
||||
LogMessage?.Trace($"Delay {Number} ms");
|
||||
Logger?.Trace($"Delay {Number} ms");
|
||||
await Task.Delay(Number ?? 0, cancellationToken).ConfigureAwait(false);
|
||||
return new NodeOutput();
|
||||
}
|
||||
|
||||
@@ -2,11 +2,20 @@
|
||||
|
||||
|
||||
<div class="row me-4 script">
|
||||
<div class="col-12 col-md-12">
|
||||
<div class="col-12 col-md-8">
|
||||
|
||||
<BootstrapLabel Value=@Localizer["Script"] ShowLabelTooltip="true" />
|
||||
<CodeEditor ShowLineNo Value=@Script ValueChanged=@Change Language="csharp" Theme="vs-dark" />
|
||||
|
||||
</div>
|
||||
<div class="col-12 col-md-4">
|
||||
|
||||
<BootstrapLabel Value=@Localizer["Tip"] ShowLabelTooltip="true" />
|
||||
<Alert Icon="fa-solid fa-circle-check" Color="Color.Success">@(new MarkupString("注意 <code>raw</code> 参数 为 <code>object</code> 类型,需要转换为实际类型操作"))</Alert>
|
||||
<Alert Icon="fa-solid fa-circle-check" Color="Color.Success">@(new MarkupString("获取设备类实体,可用 <code>GlobalData.ReadOnlyDevices</code> 字典对象,键为设备名称,值为设备对象"))</Alert>
|
||||
<Alert Icon="fa-solid fa-circle-check" Color="Color.Success">@(new MarkupString("获取变量类实体,可用方法 <code>GlobalData.GetVariable(\"设备名称1\",\"变量名称1\")</code> "))</Alert>
|
||||
<Alert Icon="fa-solid fa-circle-check" Color="Color.Success">@(new MarkupString("详细说明查看文档对应内容页面"))</Alert>
|
||||
|
||||
</div>
|
||||
<div class="col-6 col-md-6">
|
||||
<BootstrapLabel Value=@Localizer["Input"] ShowLabelTooltip="true" />
|
||||
|
||||
@@ -2,12 +2,14 @@
|
||||
|
||||
public interface INode
|
||||
{
|
||||
public TouchSocket.Core.ILog LogMessage { get; set; }
|
||||
public TouchSocket.Core.ILog Logger { get; set; }
|
||||
}
|
||||
|
||||
public interface IConditionNode : INode
|
||||
{
|
||||
public Task<bool> ExecuteAsync(NodeInput input, CancellationToken cancellationToken);
|
||||
}
|
||||
|
||||
public interface IExpressionNode : INode
|
||||
{
|
||||
public Task<NodeOutput> ExecuteAsync(NodeInput input, CancellationToken cancellationToken);
|
||||
|
||||
@@ -89,13 +89,13 @@ public class AlarmChangedTriggerNode : VariableNode, ITriggerNode, IDisposable
|
||||
{
|
||||
if (FuncDict.TryGetValue(item, out var func))
|
||||
{
|
||||
item.LogMessage?.Trace($"Alarm changed: {item.Text}");
|
||||
item.Logger?.Trace($"Alarm changed: {item.Text}");
|
||||
await func.Invoke(new NodeOutput() { Value = alarmVariable }).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
item.LogMessage?.LogWarning(ex);
|
||||
item.Logger?.LogWarning(ex);
|
||||
}
|
||||
}, Environment.ProcessorCount, token).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
@@ -71,14 +71,14 @@ public class DeviceChangedTriggerNode : TextNode, ITriggerNode, IDisposable
|
||||
{
|
||||
if (FuncDict.TryGetValue(item, out var func))
|
||||
{
|
||||
item.LogMessage?.Trace($"Device changed: {item.Text}");
|
||||
item.Logger?.Trace($"Device changed: {item.Text}");
|
||||
await func.Invoke(new NodeOutput() { Value = deviceDatas }).ConfigureAwait(false);
|
||||
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
item.LogMessage?.LogWarning(ex);
|
||||
item.Logger?.LogWarning(ex);
|
||||
}
|
||||
}, Environment.ProcessorCount, token).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
@@ -36,14 +36,14 @@ public class TimeIntervalTriggerNode : TextNode, ITriggerNode, IDisposable
|
||||
{
|
||||
if (Func != null)
|
||||
{
|
||||
LogMessage?.Trace($"Timer: {Text}");
|
||||
Logger?.Trace($"Timer: {Text}");
|
||||
await Func.Invoke(new NodeOutput() { Value = TimeTick.LastTime }).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex);
|
||||
Logger?.LogWarning(ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
||||
@@ -80,14 +80,14 @@ public class ValueChangedTriggerNode : VariableNode, ITriggerNode, IDisposable
|
||||
{
|
||||
if (FuncDict.TryGetValue(item, out var func))
|
||||
{
|
||||
item.LogMessage?.Trace($"Variable changed: {item.Text}");
|
||||
item.Logger?.Trace($"Variable changed: {item.Text}");
|
||||
await func.Invoke(new NodeOutput() { Value = variableBasicData }).ConfigureAwait(false);
|
||||
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
item.LogMessage?.LogWarning(ex);
|
||||
item.Logger?.LogWarning(ex);
|
||||
}
|
||||
}, Environment.ProcessorCount, token).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
@@ -97,7 +97,6 @@ public partial class DragAndDrop
|
||||
{
|
||||
try
|
||||
{
|
||||
System.Console.WriteLine("1");
|
||||
Value = value;
|
||||
RuleHelpers.Load(_blazorDiagram, Value);
|
||||
}
|
||||
|
||||
@@ -111,7 +111,7 @@ internal sealed class RulesEngineHostedService : BackgroundService, IRulesEngine
|
||||
private static async Task Start(RulesLog rulesLog, BlazorDiagram item, CancellationToken cancellationToken)
|
||||
{
|
||||
var startNodes = item.Nodes.Where(a => a is StartNode);
|
||||
startNodes.ForEach(a => (a as INode).LogMessage = rulesLog.Log);
|
||||
startNodes.ForEach(a => (a as INode).Logger = rulesLog.Log);
|
||||
foreach (var link in startNodes.SelectMany(a => a.PortLinks))
|
||||
{
|
||||
rulesLog.Log.Trace("Start");
|
||||
@@ -121,7 +121,7 @@ internal sealed class RulesEngineHostedService : BackgroundService, IRulesEngine
|
||||
|
||||
private static async Task Analysis(NodeModel targetNode, NodeInput input, ILog log, CancellationToken cancellationToken)
|
||||
{
|
||||
(targetNode as INode).LogMessage = log;
|
||||
(targetNode as INode).Logger = log;
|
||||
try
|
||||
{
|
||||
if (targetNode == null)
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace ThingsGateway.Plugin.DB;
|
||||
|
||||
public abstract class DynamicSQLBase
|
||||
{
|
||||
public TouchSocket.Core.ILog LogMessage { get; set; }
|
||||
public TouchSocket.Core.ILog Logger { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 建库建表
|
||||
|
||||
@@ -153,8 +153,8 @@ public partial class QuestDBProducer : BusinessBaseWithCacheIntervalVariableMode
|
||||
//必须为间隔上传
|
||||
if (!_driverPropertys.BigTextScriptHistoryTable.IsNullOrEmpty())
|
||||
{
|
||||
var hisModel = CSharpScriptEngineExtension.Do<DynamicSQLBase>(_driverPropertys.BigTextScriptHistoryTable);
|
||||
hisModel.LogMessage = LogMessage;
|
||||
DynamicSQLBase? hisModel = CSharpScriptEngineExtension.Do<DynamicSQLBase>(_driverPropertys.BigTextScriptHistoryTable);
|
||||
hisModel.Logger = LogMessage;
|
||||
await hisModel.DBInit(db, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ public partial class QuestDBProducer : BusinessBaseWithCacheIntervalVariableMode
|
||||
if (!_driverPropertys.BigTextScriptHistoryTable.IsNullOrEmpty())
|
||||
{
|
||||
var getDeviceModel = CSharpScriptEngineExtension.Do<DynamicSQLBase>(_driverPropertys.BigTextScriptHistoryTable);
|
||||
getDeviceModel.LogMessage = LogMessage;
|
||||
getDeviceModel.Logger = LogMessage;
|
||||
|
||||
await getDeviceModel.DBInsertable(db, dbInserts, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
|
||||
@@ -75,7 +75,7 @@ public partial class SqlDBProducer : BusinessBaseWithCacheIntervalVariableModel<
|
||||
{
|
||||
var getDeviceModel = CSharpScriptEngineExtension.Do<DynamicSQLBase>(_driverPropertys.BigTextScriptHistoryTable);
|
||||
|
||||
getDeviceModel.LogMessage = LogMessage;
|
||||
getDeviceModel.Logger = LogMessage;
|
||||
|
||||
await getDeviceModel.DBInsertable(db, dbInserts, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
@@ -112,7 +112,7 @@ public partial class SqlDBProducer : BusinessBaseWithCacheIntervalVariableModel<
|
||||
if (!_driverPropertys.BigTextScriptRealTable.IsNullOrEmpty())
|
||||
{
|
||||
var getDeviceModel = CSharpScriptEngineExtension.Do<DynamicSQLBase>(_driverPropertys.BigTextScriptRealTable);
|
||||
getDeviceModel.LogMessage = LogMessage;
|
||||
getDeviceModel.Logger = LogMessage;
|
||||
|
||||
await getDeviceModel.DBInsertable(db, datas, cancellationToken).ConfigureAwait(false);
|
||||
return OperResult.Success;
|
||||
|
||||
@@ -72,7 +72,7 @@ public partial class TDengineDBProducer : BusinessBaseWithCacheIntervalVariableM
|
||||
if (!_driverPropertys.BigTextScriptHistoryTable.IsNullOrEmpty())
|
||||
{
|
||||
var getDeviceModel = CSharpScriptEngineExtension.Do<DynamicSQLBase>(_driverPropertys.BigTextScriptHistoryTable);
|
||||
getDeviceModel.LogMessage = LogMessage;
|
||||
getDeviceModel.Logger = LogMessage;
|
||||
await getDeviceModel.DBInsertable(db, dbInserts, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<Version>10.2.3</Version>
|
||||
<Version>10.2.4</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
Reference in New Issue
Block a user