Compare commits

...

3 Commits

Author SHA1 Message Date
Diego
e97ee9b64b 10.5.15 2025-05-07 22:08:54 +08:00
Diego
6a03e39eeb 10.5.14 2025-05-07 22:00:31 +08:00
Diego
525ec740b5 添加脚本demo 2025-05-06 11:43:56 +08:00
29 changed files with 692 additions and 56 deletions

View File

@@ -10,6 +10,8 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel;
using Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption;
using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.StaticFiles;
@@ -17,6 +19,7 @@ using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Text.Encodings.Web;
@@ -27,6 +30,7 @@ using ThingsGateway.Admin.Razor;
using ThingsGateway.Extension;
using ThingsGateway.Logging;
using ThingsGateway.NewLife.Caching;
using Microsoft.AspNetCore.DataProtection;
namespace ThingsGateway.AdminServer;
@@ -291,6 +295,21 @@ public class Startup : AppStartup
services.AddAuthorizationCore();
services.AddScoped<IAuthorizationHandler, BlazorServerAuthenticationHandler>();
services.AddScoped<AuthenticationStateProvider, BlazorServerAuthenticationStateProvider>();
#if NET9_0_OR_GREATER
var certificate = X509CertificateLoader.LoadPkcs12FromFile("ThingsGateway.pfx", "ThingsGateway", X509KeyStorageFlags.EphemeralKeySet);
#else
var certificate = new X509Certificate2("ThingsGateway.pfx", "ThingsGateway", X509KeyStorageFlags.EphemeralKeySet);
#endif
services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo("../keys"))
.ProtectKeysWithCertificate(certificate)
.UseCryptographicAlgorithms(new AuthenticatedEncryptorConfiguration
{
EncryptionAlgorithm = EncryptionAlgorithm.AES_256_CBC,
ValidationAlgorithm = ValidationAlgorithm.HMACSHA256
});
}

View File

@@ -72,6 +72,9 @@
<None Update="pm2-linux.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="ThingsGateway.pfx">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="thingsgateway.service">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>

Binary file not shown.

View File

@@ -1,8 +1,8 @@
<Project>
<PropertyGroup>
<PluginVersion>10.5.12</PluginVersion>
<ProPluginVersion>10.5.12</ProPluginVersion>
<PluginVersion>10.5.15</PluginVersion>
<ProPluginVersion>10.5.15</ProPluginVersion>
<AuthenticationVersion>2.1.7</AuthenticationVersion>
</PropertyGroup>

View File

@@ -562,6 +562,17 @@ public abstract class DeviceBase : DisposableObject, IDevice
finally
{
waitLock.Release();
if (waitData.WaitResult != null)
{
if (waitData.WaitResult.Sign != sign)
{
waitData.WaitResult.Sign = sign;
}
}
else
{
waitData.SetResult(new MessageBase() { Sign = sign });
}
clientChannel.WaitHandlePool.Destroy(waitData);
Channel.ChannelReceivedWaitDict.TryRemove(sign, out _);
}

View File

@@ -40,9 +40,7 @@ public class AsyncReadWriteLock
private void ReleaseWriter()
{
Interlocked.Decrement(ref _writerCount);
if (Interlocked.Read(ref _writerCount) == 0)
if (Interlocked.Decrement(ref _writerCount) == 0)
{
var resetEvent = _readerLock;
_readerLock = new(false);

View File

@@ -1,32 +0,0 @@
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://thingsgateway.cn/
// QQ群605534569
//------------------------------------------------------------------------------
using BootstrapBlazor.Components;
namespace ThingsGateway.Gateway.Application;
/// <summary>
/// <inheritdoc/>
/// </summary>
public class BusinessPropertyWithCacheIntervalDBScript : BusinessPropertyWithCacheInterval
{
/// <summary>
/// 表定义实体脚本
/// </summary>
[DynamicProperty]
[AutoGenerateColumn(ComponentType = typeof(Textarea), Rows = 3)]
public string? BigTextScriptTableModel { get; set; }
/// <summary>
/// 数据脚本
/// </summary>
[AutoGenerateColumn(ComponentType = typeof(Textarea), Rows = 3)]
public string? BigTextScriptDataModel { get; set; }
}

View File

@@ -26,7 +26,7 @@ namespace ThingsGateway.Gateway.Application;
public class DeviceRuntime : Device, IDisposable
{
protected volatile DeviceStatusEnum _deviceStatus = DeviceStatusEnum.Default;
private string? _lastErrorMessage;
/// <summary>

View File

@@ -129,7 +129,6 @@ public partial class PropertyComponent : IPropertyUIBase
return;
}
var op = new DialogOption()
{
IsScrolling = true,
@@ -144,6 +143,147 @@ public partial class PropertyComponent : IPropertyUIBase
{
{nameof(ScriptCheck.Data),data },
{nameof(ScriptCheck.Script),script },
{nameof(ScriptCheck.OnGetDemo),()=>
{
return
pname == nameof(BusinessPropertyWithCacheIntervalScript.BigTextScriptDeviceModel)?
"""
using ThingsGateway.Foundation;
using System.Dynamic;
using TouchSocket.Core;
public class S1 : IDynamicModel
{
public IEnumerable<dynamic> GetList(IEnumerable<object> datas)
{
List<ExpandoObject> deviceObjs = new List<ExpandoObject>();
foreach (var v in datas)
{
var device = (DeviceBasicData)v;
var expando = new ExpandoObject();
var deviceObj = new ExpandoObject();
deviceObj.TryAdd(nameof(Device.Description), device.Description);
deviceObj.TryAdd(nameof(DeviceBasicData.ActiveTime), device.ActiveTime);
deviceObj.TryAdd(nameof(DeviceBasicData.DeviceStatus), device.DeviceStatus.ToString());
deviceObj.TryAdd(nameof(DeviceBasicData.LastErrorMessage), device.LastErrorMessage);
deviceObj.TryAdd(nameof(DeviceBasicData.PluginName), device.PluginName);
deviceObj.TryAdd(nameof(DeviceBasicData.Remark1), device.Remark1);
deviceObj.TryAdd(nameof(DeviceBasicData.Remark2), device.Remark2);
deviceObj.TryAdd(nameof(DeviceBasicData.Remark3), device.Remark3);
deviceObj.TryAdd(nameof(DeviceBasicData.Remark4), device.Remark4);
deviceObj.TryAdd(nameof(DeviceBasicData.Remark5), device.Remark5);
expando.TryAdd(nameof(Device.Name), deviceObj);
}
return deviceObjs;
}
}
"""
:
pname == nameof(BusinessPropertyWithCacheIntervalScript.BigTextScriptVariableModel)?
"""
using System.Dynamic;
using ThingsGateway.Foundation;
using TouchSocket.Core;
public class S2 : IDynamicModel
{
public IEnumerable<dynamic> GetList(IEnumerable<object> datas)
{
List<ExpandoObject> deviceObjs = new List<ExpandoObject>();
//按设备名称分组
var groups = datas.Where(a => !string.IsNullOrEmpty(((VariableBasicData)a).DeviceName)).GroupBy(a => ((VariableBasicData)a).DeviceName, a => ((VariableBasicData)a));
foreach (var group in groups)
{
//按采集时间分组
var data = group.GroupBy(a => a.CollectTime.DateTimeToUnixTimestamp());
var deviceObj = new ExpandoObject();
List<ExpandoObject> expandos = new List<ExpandoObject>();
foreach (var item in data)
{
var expando = new ExpandoObject();
expando.TryAdd("ts", item.Key);
var variableObj = new ExpandoObject();
foreach (var tag in item)
{
variableObj.TryAdd(tag.Name, tag.Value);
}
expando.TryAdd("values", variableObj);
expandos.Add(expando);
}
deviceObj.TryAdd(group.Key, expandos);
deviceObjs.Add(deviceObj);
}
return deviceObjs;
}
}
"""
:
pname == nameof(BusinessPropertyWithCacheIntervalScript.BigTextScriptAlarmModel)?
"""
using System.Dynamic;
using ThingsGateway.Foundation;
using TouchSocket.Core;
public class DeviceScript : IDynamicModel
{
public IEnumerable<dynamic> GetList(IEnumerable<object> datas)
{
List<ExpandoObject> deviceObjs = new List<ExpandoObject>();
//按设备名称分组
var groups = datas.Where(a => !string.IsNullOrEmpty(((AlarmVariable)a).DeviceName)).GroupBy(a => ((AlarmVariable)a).DeviceName, a => ((AlarmVariable)a));
foreach (var group in groups)
{
//按采集时间分组
var data = group.GroupBy(a => a.AlarmTime.DateTimeToUnixTimestamp());
var deviceObj = new ExpandoObject();
List<ExpandoObject> expandos = new List<ExpandoObject>();
foreach (var item in data)
{
var expando = new ExpandoObject();
expando.TryAdd("ts", item.Key);
var variableObj = new ExpandoObject();
foreach (var tag in item)
{
var alarmObj = new ExpandoObject();
alarmObj.TryAdd(nameof(tag.AlarmCode), tag.AlarmCode);
alarmObj.TryAdd(nameof(tag.AlarmText), tag.AlarmText);
alarmObj.TryAdd(nameof(tag.AlarmType), tag.AlarmType);
alarmObj.TryAdd(nameof(tag.AlarmLimit), tag.AlarmLimit);
alarmObj.TryAdd(nameof(tag.EventTime), tag.EventTime);
alarmObj.TryAdd(nameof(tag.EventType), tag.EventType);
variableObj.TryAdd(tag.Name, alarmObj);
}
expando.TryAdd("alarms", variableObj);
expandos.Add(expando);
}
deviceObj.TryAdd(group.Key, expandos);
deviceObjs.Add(deviceObj);
}
return deviceObjs;
}
}
"""
:
""
;
}
},
{nameof(ScriptCheck.ScriptChanged),EventCallback.Factory.Create<string>(this, v =>
{
if (pname == nameof(BusinessPropertyWithCacheIntervalScript.BigTextScriptAlarmModel))
@@ -171,3 +311,7 @@ public partial class PropertyComponent : IPropertyUIBase
[Inject]
private DialogService DialogService { get; set; }
}

View File

@@ -18,6 +18,8 @@
<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>
<Button IsAsync OnClick="GetDemo" class="mt-3" Text="Demo" />
</div>
<div class="col-6 col-md-6">
<BootstrapLabel Value=@Localizer["Input"] ShowLabelTooltip="true" />

View File

@@ -8,6 +8,8 @@
// QQ群605534569
//------------------------------------------------------------------------------
using System.Threading.Tasks;
using ThingsGateway.Gateway.Application;
using ThingsGateway.NewLife.Json.Extension;
@@ -56,4 +58,13 @@ public partial class ScriptCheck
}
[Inject]
private IStringLocalizer<DeviceEditComponent> Localizer { get; set; }
private async Task GetDemo(Microsoft.AspNetCore.Components.Web.MouseEventArgs args)
{
Script = OnGetDemo?.Invoke();
await Change(Script);
}
[Parameter, EditorRequired]
public Func<string> OnGetDemo { get; set; }
}

View File

@@ -9,7 +9,64 @@ namespace ThingsGateway.RulesEngine;
[CategoryNode(Category = "Actuator", ImgUrl = "_content/ThingsGateway.RulesEngine/img/CSharpScript.svg", Desc = nameof(ExecuteScriptNode), LocalizerType = typeof(ThingsGateway.RulesEngine._Imports), WidgetType = typeof(CSharpScriptWidget))]
public class ExecuteScriptNode : TextNode, IActuatorNode, IExexcuteExpressionsBase, IDisposable
{
public ExecuteScriptNode(string id, Point? position = null) : base(id, position) { Title = "ExecuteScriptNode"; Placeholder = "ExecuteScriptNode.Placeholder"; }
public ExecuteScriptNode(string id, Point? position = null) : base(id, position)
{
Title = "ExecuteScriptNode"; Placeholder = "ExecuteScriptNode.Placeholder";
Text =
"""
using ThingsGateway.RulesEngine;
using ThingsGateway.Foundation;
using TouchSocket.Core;
using System.Text;
public class TestEx : IExexcuteExpressions
{
public TouchSocket.Core.ILog Logger { get; set; }
public async System.Threading.Tasks.Task<NodeOutput> ExecuteAsync(NodeInput input, System.Threading.CancellationToken cancellationToken)
{
//想上传mqtt可以自己写mqtt上传代码或者通过mqtt插件的公开方法上传
//直接获取mqttclient插件类型的第一个设备
var driver = GlobalData.ReadOnlyChannels.FirstOrDefault(a => a.Value.PluginName == "ThingsGateway.Plugin.Mqtt.MqttClient").Value?.ReadDeviceRuntimes?.FirstOrDefault().Value?.Driver;
if (driver != null)
{
//找到对应的MqttClient插件设备
var mqttClient = (ThingsGateway.Plugin.Mqtt.MqttClient)driver;
if (mqttClient == null)
throw new("mqttClient NOT FOUND");
var result = await mqttClient.MqttUpAsync("test", Encoding.UTF8.GetBytes("test"),1, default);// 主题 和 负载
if (!result.IsSuccess)
throw new(result.ErrorMessage);
return new NodeOutput() { Value = result };
}
throw new("mqttClient NOT FOUND");
//通过设备名称找出mqttClient插件
//var driver = GlobalData.ReadOnlyDevices.FirstOrDefault(a => a.Value.Name == "mqttDevice1").Value?.Driver;
//if (driver != null)
//{
// //找到对应的MqttClient插件设备
// var mqttClient = (ThingsGateway.Plugin.Mqtt.MqttClient)driver;
// if (mqttClient == null)
// throw new("mqttClient NOT FOUND");
// var result = await mqttClient.MqttUpAsync("test", "test", default);// 主题 和 负载
// if (!result.IsSuccess)
// throw new(result.ErrorMessage);
// return new NodeOutput() { Value = result };
//}
//throw new("mqttClient NOT FOUND");
}
}
""";
}
private string text;

View File

@@ -11,7 +11,14 @@ namespace ThingsGateway.RulesEngine;
[CategoryNode(Category = "Expression", ImgUrl = "_content/ThingsGateway.RulesEngine/img/CSharpScript.svg", Desc = nameof(ConditionNode), LocalizerType = typeof(ThingsGateway.RulesEngine._Imports), WidgetType = typeof(CSharpScriptWidget))]
public class ConditionNode : TextNode, IConditionNode
{
public ConditionNode(string id, Point? position = null) : base(id, position) { Title = "ConditionNode"; Placeholder = "ConditionNode.Placeholder"; }
public ConditionNode(string id, Point? position = null) : base(id, position)
{
Title = "ConditionNode"; Placeholder = "ConditionNode.Placeholder";
Text = "return true;";
}
Task<bool> IConditionNode.ExecuteAsync(NodeInput input, CancellationToken cancellationToken)
{

View File

@@ -8,7 +8,12 @@ namespace ThingsGateway.RulesEngine;
[CategoryNode(Category = "Expression", ImgUrl = "_content/ThingsGateway.RulesEngine/img/CSharpScript.svg", Desc = nameof(DataNode), LocalizerType = typeof(ThingsGateway.RulesEngine._Imports), WidgetType = typeof(CSharpScriptWidget))]
public class DataNode : TextNode, IExpressionNode
{
public DataNode(string id, Point? position = null) : base(id, position) { Title = "DataNode"; Placeholder = "DataNode.Placeholder"; }
public DataNode(string id, Point? position = null) : base(id, position)
{
Title = "DataNode"; Placeholder = "DataNode.Placeholder";
Text = "return 1;";
}
Task<NodeOutput> IExpressionNode.ExecuteAsync(NodeInput input, CancellationToken cancellationToken)
{

View File

@@ -398,10 +398,10 @@ public partial class SiemensS7Master : DeviceBase
try
{
var result2 = await GetResponsedDataAsync(new S7Send(ISO_CR), channel, Timeout).ConfigureAwait(false);
var result2 = await SendThenReturnMessageBaseAsync(new S7Send(ISO_CR), channel).ConfigureAwait(false);
if (!result2.IsSuccess)
{
Logger?.LogWarning(SiemensS7Resource.Localizer["HandshakeError1", channel.ToString(), result2.ErrorMessage]);
Logger?.LogWarning(SiemensS7Resource.Localizer["HandshakeError1", channel.ToString(), result2]);
await channel.CloseAsync().ConfigureAwait(false);
return true;
}
@@ -409,16 +409,21 @@ public partial class SiemensS7Master : DeviceBase
catch (OperationCanceledException) { }
catch (Exception ex)
{
Logger?.LogWarning(SiemensS7Resource.Localizer["HandshakeError1", channel.ToString(), ex.Message]);
Logger?.LogWarning(SiemensS7Resource.Localizer["HandshakeError1", channel.ToString(), ex]);
await channel.CloseAsync().ConfigureAwait(false);
return true;
}
try
{
var result2 = await GetResponsedDataAsync(new S7Send(S7_PN), channel, Timeout).ConfigureAwait(false);
var result2 = await SendThenReturnMessageBaseAsync(new S7Send(S7_PN), channel).ConfigureAwait(false);
if (!result2.IsSuccess)
{
Logger?.LogWarning(SiemensS7Resource.Localizer["HandshakeError2", channel.ToString(), result2.ErrorMessage]);
Logger?.LogWarning(SiemensS7Resource.Localizer["HandshakeError2", channel.ToString(), result2]);
await channel.CloseAsync().ConfigureAwait(false);
return true;
}
if (result2.Content == null)
{
await channel.CloseAsync().ConfigureAwait(false);
return true;
}
@@ -429,7 +434,7 @@ public partial class SiemensS7Master : DeviceBase
catch (OperationCanceledException) { }
catch (Exception ex)
{
Logger?.LogWarning(SiemensS7Resource.Localizer["HandshakeError2", channel.ToString(), ex.Message]);
Logger?.LogWarning(SiemensS7Resource.Localizer["HandshakeError2", channel.ToString(), ex]);
await channel.CloseAsync().ConfigureAwait(false);
return true;
}

View File

@@ -25,11 +25,20 @@
<div class="col-12 col-md-12">
<BootstrapLabel Value=@SqlDBProducerPropertyLocalizer["BigTextScriptHistoryTable"] ShowLabelTooltip="true" />
<CodeEditor @bind-Value=@businessProperty.BigTextScriptHistoryTable Language="csharp" Theme="vs-dark" />
<div class="ms-2 d-flex justify-content-center align-items-center">
<Button IsDisabled=@(!CanWrite) OnClick="()=>CheckScript(businessProperty,nameof(businessProperty.BigTextScriptHistoryTable))">
@RazorLocalizer["Check"]
</Button>
</div>
</div>
<div class="col-12 col-md-12">
<BootstrapLabel Value=@SqlDBProducerPropertyLocalizer["BigTextScriptRealTable"] ShowLabelTooltip="true" />
<CodeEditor @bind-Value=@businessProperty.BigTextScriptRealTable Language="csharp" Theme="vs-dark" />
<div class="ms-2 d-flex justify-content-center align-items-center">
<Button IsDisabled=@(!CanWrite) OnClick="()=>CheckScript(businessProperty,nameof(businessProperty.BigTextScriptRealTable))">
@RazorLocalizer["Check"]
</Button>
</div>
</div>
</EditTemplate>
</EditorItem>

View File

@@ -8,17 +8,22 @@
// QQ群605534569
// ------------------------------------------------------------------------------
#pragma warning disable CA2007 // 考虑对等待的任务调用 ConfigureAwait
using BootstrapBlazor.Components;
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.Localization;
using ThingsGateway.Gateway.Razor;
using ThingsGateway.Plugin.SqlDB;
using ThingsGateway.Razor;
namespace ThingsGateway.Debug
{
public partial class SqlDBProducerPropertyRazor : IPropertyUIBase
{
[Inject]
IStringLocalizer<ThingsGateway.Razor._Imports> RazorLocalizer { get; set; }
[Parameter, EditorRequired]
@@ -39,6 +44,144 @@ namespace ThingsGateway.Debug
return base.OnParametersSetAsync();
}
private async Task CheckScript(SqlDBProducerProperty businessProperty, string pname)
{
IEnumerable<object> data = null;
string script = null;
{
data = new List<VariableBasicData>() { new() {
Name = "testName",
DeviceName = "testDevice",
Value = "1",
ChangeTime = DateTime.Now,
CollectTime = DateTime.Now,
Remark1="1",
Remark2="2",
Remark3="3",
Remark4="4",
Remark5="5",
} ,
new() {
Name = "testName2",
DeviceName = "testDevice",
Value = "1",
ChangeTime = DateTime.Now,
CollectTime = DateTime.Now,
Remark1="1",
Remark2="2",
Remark3="3",
Remark4="4",
Remark5="5",
} };
script = pname == businessProperty.BigTextScriptHistoryTable ? businessProperty.BigTextScriptHistoryTable : businessProperty.BigTextScriptRealTable;
}
var op = new DialogOption()
{
IsScrolling = true,
Title = RazorLocalizer["Check"],
ShowFooter = false,
ShowCloseButton = false,
Size = Size.ExtraExtraLarge,
FullScreenSize = FullScreenSize.None
};
op.Component = BootstrapDynamicComponent.CreateComponent<ScriptCheck>(new Dictionary<string, object?>
{
{nameof(ScriptCheck.Data),data },
{nameof(ScriptCheck.Script),script },
{nameof(ScriptCheck.OnGetDemo),()=>
{
return
pname == nameof(SqlDBProducerProperty.BigTextScriptHistoryTable)?
""""
using ThingsGateway.Foundation;
using System.Dynamic;
using TouchSocket.Core;
public class S1 : DynamicSQLBase
{
public override async Task DBInit(ISqlSugarClient db, CancellationToken cancellationToken)
{
var sql = $"""
""";
await db.Ado.ExecuteCommandAsync(sql, default, cancellationToken: cancellationToken).ConfigureAwait(false);
}
public override async Task DBInsertable(ISqlSugarClient db, IEnumerable<object> datas, CancellationToken cancellationToken)
{
var sql = $"""
""";
await db.Ado.ExecuteCommandAsync(sql, default, cancellationToken: cancellationToken).ConfigureAwait(false);
}
}
""""
:
pname == nameof(SqlDBProducerProperty.BigTextScriptRealTable)?
""""
using System.Dynamic;
using ThingsGateway.Foundation;
using TouchSocket.Core;
public class S1 : DynamicSQLBase
{
public override async Task DBInit(ISqlSugarClient db, CancellationToken cancellationToken)
{
var sql = $"""
""";
await db.Ado.ExecuteCommandAsync(sql, default, cancellationToken: cancellationToken).ConfigureAwait(false);
}
public override async Task DBInsertable(ISqlSugarClient db, IEnumerable<object> datas, CancellationToken cancellationToken)
{
var sql = $"""
""";
await db.Ado.ExecuteCommandAsync(sql, default, cancellationToken: cancellationToken).ConfigureAwait(false);
}
}
""""
:
""
;
}
},
{nameof(ScriptCheck.ScriptChanged),EventCallback.Factory.Create<string>(this, v =>
{
if (pname == nameof(SqlDBProducerProperty.BigTextScriptHistoryTable))
{
businessProperty.BigTextScriptHistoryTable=v;
}
}
else if (pname == nameof(SqlDBProducerProperty.BigTextScriptRealTable))
{
businessProperty.BigTextScriptRealTable=v;
}
}) },
});
await DialogService.Show(op);
}
[Inject]
DialogService DialogService { get; set; }
}
}

View File

@@ -46,7 +46,6 @@ namespace ThingsGateway.Plugin.Mqtt
if (mqttClientProperty.TLS == true)
{
{
var filePath = Path.Combine("PluginFile", Id, nameof(mqttClientProperty.CAFile));
if (!Directory.Exists(filePath))//如果不存在就创建文件夹
Directory.CreateDirectory(filePath);
@@ -230,7 +229,6 @@ namespace ThingsGateway.Plugin.Mqtt
return;
}
var op = new DialogOption()
{
IsScrolling = true,
@@ -245,6 +243,142 @@ namespace ThingsGateway.Plugin.Mqtt
{
{nameof(ScriptCheck.Data),data },
{nameof(ScriptCheck.Script),script },
{nameof(ScriptCheck.OnGetDemo),()=>
{
return
pname == nameof(BusinessPropertyWithCacheIntervalScript.BigTextScriptDeviceModel)?
"""
using TouchSocket.Core;
public class S1 : IDynamicModel
{
public IEnumerable<dynamic> GetList(IEnumerable<object> datas)
{
List<ExpandoObject> deviceObjs = new List<ExpandoObject>();
foreach (var v in datas)
{
var device = (DeviceBasicData)v;
var expando = new ExpandoObject();
var deviceObj = new ExpandoObject();
deviceObj.TryAdd(nameof(Device.Description), device.Description);
deviceObj.TryAdd(nameof(DeviceBasicData.ActiveTime), device.ActiveTime);
deviceObj.TryAdd(nameof(DeviceBasicData.DeviceStatus), device.DeviceStatus.ToString());
deviceObj.TryAdd(nameof(DeviceBasicData.LastErrorMessage), device.LastErrorMessage);
deviceObj.TryAdd(nameof(DeviceBasicData.PluginName), device.PluginName);
deviceObj.TryAdd(nameof(DeviceBasicData.Remark1), device.Remark1);
deviceObj.TryAdd(nameof(DeviceBasicData.Remark2), device.Remark2);
deviceObj.TryAdd(nameof(DeviceBasicData.Remark3), device.Remark3);
deviceObj.TryAdd(nameof(DeviceBasicData.Remark4), device.Remark4);
deviceObj.TryAdd(nameof(DeviceBasicData.Remark5), device.Remark5);
expando.TryAdd(nameof(Device.Name), deviceObj);
}
return deviceObjs;
}
}
"""
:
pname == nameof(BusinessPropertyWithCacheIntervalScript.BigTextScriptVariableModel)?
"""
using TouchSocket.Core;
public class S2 : IDynamicModel
{
public IEnumerable<dynamic> GetList(IEnumerable<object> datas)
{
List<ExpandoObject> deviceObjs = new List<ExpandoObject>();
//按设备名称分组
var groups = datas.Where(a => !string.IsNullOrEmpty(((VariableBasicData)a).DeviceName)).GroupBy(a => ((VariableBasicData)a).DeviceName, a => ((VariableBasicData)a));
foreach (var group in groups)
{
//按采集时间分组
var data = group.GroupBy(a => a.CollectTime.DateTimeToUnixTimestamp());
var deviceObj = new ExpandoObject();
List<ExpandoObject> expandos = new List<ExpandoObject>();
foreach (var item in data)
{
var expando = new ExpandoObject();
expando.TryAdd("ts", item.Key);
var variableObj = new ExpandoObject();
foreach (var tag in item)
{
variableObj.TryAdd(tag.Name, tag.Value);
}
expando.TryAdd("values", variableObj);
expandos.Add(expando);
}
deviceObj.TryAdd(group.Key, expandos);
deviceObjs.Add(deviceObj);
}
return deviceObjs;
}
}
"""
:
pname == nameof(BusinessPropertyWithCacheIntervalScript.BigTextScriptAlarmModel)?
"""
using TouchSocket.Core;
public class DeviceScript : IDynamicModel
{
public IEnumerable<dynamic> GetList(IEnumerable<object> datas)
{
List<ExpandoObject> deviceObjs = new List<ExpandoObject>();
//按设备名称分组
var groups = datas.Where(a => !string.IsNullOrEmpty(((AlarmVariable)a).DeviceName)).GroupBy(a => ((AlarmVariable)a).DeviceName, a => ((AlarmVariable)a));
foreach (var group in groups)
{
//按采集时间分组
var data = group.GroupBy(a => a.AlarmTime.DateTimeToUnixTimestamp());
var deviceObj = new ExpandoObject();
List<ExpandoObject> expandos = new List<ExpandoObject>();
foreach (var item in data)
{
var expando = new ExpandoObject();
expando.TryAdd("ts", item.Key);
var variableObj = new ExpandoObject();
foreach (var tag in item)
{
var alarmObj = new ExpandoObject();
alarmObj.TryAdd(nameof(tag.AlarmCode), tag.AlarmCode);
alarmObj.TryAdd(nameof(tag.AlarmText), tag.AlarmText);
alarmObj.TryAdd(nameof(tag.AlarmType), tag.AlarmType);
alarmObj.TryAdd(nameof(tag.AlarmLimit), tag.AlarmLimit);
alarmObj.TryAdd(nameof(tag.EventTime), tag.EventTime);
alarmObj.TryAdd(nameof(tag.EventType), tag.EventType);
variableObj.TryAdd(tag.Name, alarmObj);
}
expando.TryAdd("alarms", variableObj);
expandos.Add(expando);
}
deviceObj.TryAdd(group.Key, expandos);
deviceObjs.Add(deviceObj);
}
return deviceObjs;
}
}
"""
:
""
;
}
},
{nameof(ScriptCheck.ScriptChanged),EventCallback.Factory.Create<string>(this, v =>
{
if (pname == nameof(BusinessPropertyWithCacheIntervalScript.BigTextScriptAlarmModel))
@@ -269,6 +403,7 @@ namespace ThingsGateway.Plugin.Mqtt
}
[Inject]
private DialogService DialogService { get; set; }
}

View File

@@ -202,6 +202,7 @@ public partial class OpcUaServer : BusinessBase
success = true;
}
}
catch (OperationCanceledException) { }
catch (Exception ex)
{
if (success)

View File

@@ -0,0 +1,39 @@
{
"profiles": {
"http": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"dotnetRunMessages": true,
"applicationUrl": "http://*:5000"
},
"demo": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Demo"
},
"dotnetRunMessages": true,
"applicationUrl": "http://*:5000"
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
},
"$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://*:59494/",
"sslPort": 44372
}
}
}

View File

@@ -11,6 +11,9 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption;
using Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.HttpOverrides;
@@ -24,6 +27,7 @@ using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Text.Encodings.Web;
using System.Text.Unicode;
@@ -273,6 +277,21 @@ public class Startup : AppStartup
services.AddSignalR();
#endregion
#if NET9_0_OR_GREATER
var certificate = X509CertificateLoader.LoadPkcs12FromFile("ThingsGateway.pfx", "ThingsGateway", X509KeyStorageFlags.EphemeralKeySet);
#else
var certificate = new X509Certificate2("ThingsGateway.pfx", "ThingsGateway", X509KeyStorageFlags.EphemeralKeySet);
#endif
services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo("../keys"))
.ProtectKeysWithCertificate(certificate)
.UseCryptographicAlgorithms(new AuthenticatedEncryptorConfiguration
{
EncryptionAlgorithm = EncryptionAlgorithm.AES_256_CBC,
ValidationAlgorithm = ValidationAlgorithm.HMACSHA256
});
}

View File

@@ -3,7 +3,7 @@
<Import Project="$(SolutionDir)Version.props" />
<ItemGroup Condition=" '$(SolutionName)' != 'ThingsGatewayRelease' " >
<ItemGroup Condition=" '$(SolutionName)' != 'ThingsGatewayRelease' ">
<ProjectReference Include="..\Gateway\ThingsGateway.Gateway.Application\ThingsGateway.Gateway.Application.csproj" />
<ProjectReference Include="..\Gateway\ThingsGateway.Gateway.Razor\ThingsGateway.Gateway.Razor.csproj" />
<ProjectReference Include="..\Gateway\ThingsGateway.Management\ThingsGateway.Management.csproj" />
@@ -19,8 +19,8 @@
<!--nuget包解压复制文件上下文动态加载网关管理和网关冗余-->
<Import Project="..\ThingsGateway.Server\targets\GatewayOther.targets" Condition=" '$(SolutionName)' == 'ThingsGatewayRelease' " />
<ItemGroup Condition=" '$(SolutionName)' == 'ThingsGatewayRelease' " >
<PackageReference Include="ThingsGateway.Photino.Blazor" Version="$(Version)" />
<ItemGroup Condition=" '$(SolutionName)' == 'ThingsGatewayRelease' ">
<PackageReference Include="ThingsGateway.Photino.Blazor" Version="$(Version)" />
</ItemGroup>
@@ -87,6 +87,9 @@
<Compile Include="..\ThingsGateway.Server\Program\SingleFilePublish.cs" Link="Program\SingleFilePublish.cs" />
<Content Include="..\ThingsGateway.Server\ThingsGateway.pfx" Link="ThingsGateway.pfx">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="..\ThingsGateway.Server\wwwroot\favicon.ico" Link="wwwroot\favicon.ico" />
@@ -119,11 +122,23 @@
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<Content Remove="launchSettings.json" />
</ItemGroup>
<ItemGroup>
<Content Include="favicon.ico">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<None Include="Properties\launchSettings.json">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>Never</CopyToPublishDirectory>
</None>
</ItemGroup>
</Project>

View File

@@ -10,6 +10,9 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel;
using Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.StaticFiles;
@@ -27,6 +30,7 @@ using ThingsGateway.Admin.Razor;
using ThingsGateway.Extension;
using ThingsGateway.Logging;
using ThingsGateway.NewLife.Caching;
using System.Security.Cryptography.X509Certificates;
namespace ThingsGateway.Server;
@@ -291,6 +295,21 @@ public class Startup : AppStartup
services.AddAuthorizationCore();
services.AddScoped<IAuthorizationHandler, BlazorServerAuthenticationHandler>();
services.AddScoped<AuthenticationStateProvider, BlazorServerAuthenticationStateProvider>();
#if NET9_0_OR_GREATER
var certificate = X509CertificateLoader.LoadPkcs12FromFile("ThingsGateway.pfx", "ThingsGateway", X509KeyStorageFlags.EphemeralKeySet);
#else
var certificate = new X509Certificate2("ThingsGateway.pfx", "ThingsGateway",X509KeyStorageFlags.EphemeralKeySet);
#endif
services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo("../keys"))
.ProtectKeysWithCertificate(certificate)
.UseCryptographicAlgorithms(new AuthenticatedEncryptorConfiguration
{
EncryptionAlgorithm = EncryptionAlgorithm.AES_256_CBC,
ValidationAlgorithm = ValidationAlgorithm.HMACSHA256
});
}

View File

@@ -95,6 +95,9 @@
<Content Include="favicon.ico">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<None Update="ThingsGateway.pfx">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="WindowsService">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>

Binary file not shown.

View File

@@ -10,6 +10,9 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel;
using Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.StaticFiles;
@@ -26,6 +29,8 @@ using ThingsGateway.Admin.Application;
using ThingsGateway.Admin.Razor;
using ThingsGateway.Extension;
using ThingsGateway.Logging;
using System.Security.Cryptography.X509Certificates;
using System.Security;
namespace ThingsGateway.UpgradeServer;
@@ -297,6 +302,21 @@ public class Startup : AppStartup
services.AddAuthorizationCore();
services.AddScoped<IAuthorizationHandler, BlazorServerAuthenticationHandler>();
services.AddScoped<AuthenticationStateProvider, BlazorServerAuthenticationStateProvider>();
#if NET9_0_OR_GREATER
var certificate = X509CertificateLoader.LoadPkcs12FromFile("ThingsGateway.pfx", "ThingsGateway", X509KeyStorageFlags.EphemeralKeySet);
#else
var certificate = new X509Certificate2("ThingsGateway.pfx", "ThingsGateway",X509KeyStorageFlags.EphemeralKeySet);
#endif
services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo("../keys"))
.ProtectKeysWithCertificate(certificate)
.UseCryptographicAlgorithms(new AuthenticatedEncryptorConfiguration
{
EncryptionAlgorithm = EncryptionAlgorithm.AES_256_CBC,
ValidationAlgorithm = ValidationAlgorithm.HMACSHA256
});
}

View File

@@ -76,6 +76,9 @@
<None Update="pm2-linux.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="ThingsGateway.pfx">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="WindowsServiceDelete.bat">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>

View File

@@ -1,6 +1,6 @@
<Project>
<PropertyGroup>
<Version>10.5.12</Version>
<Version>10.5.15</Version>
</PropertyGroup>
<ItemGroup>