Compare commits

...

12 Commits

Author SHA1 Message Date
Diego
03c0dfef37 增加业务设备日志 2025-05-12 15:26:51 +08:00
Diego
6ef6929c35 优化api权限树 2025-05-12 10:21:41 +08:00
Diego
e3c0c173f0 更新依赖 2025-05-12 08:53:25 +08:00
Diego
7d64e058d4 更新依赖 2025-05-08 16:34:48 +08:00
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
2248356998 qq.com
b790cf5f4e 更新依赖 2025-05-05 20:25:43 +08:00
Diego
d1248811fd build: 10.5.11 2025-04-30 23:05:36 +08:00
2248356998 qq.com
022d016e8e feat: 添加采集组 2025-04-30 23:04:51 +08:00
Diego
f73245e650 build: 10.5.10 2025-04-30 15:31:39 +08:00
2248356998 qq.com
484461fa05 更新依赖 2025-04-30 15:29:19 +08:00
84 changed files with 1065 additions and 364 deletions

View File

@@ -26,6 +26,7 @@ namespace ThingsGateway.Admin.Application;
[Route("openapi/auth")] [Route("openapi/auth")]
[Authorize(AuthenticationSchemes = "Bearer")] [Authorize(AuthenticationSchemes = "Bearer")]
[LoggingMonitor] [LoggingMonitor]
[ApiController]
public class OpenApiController : ControllerBase public class OpenApiController : ControllerBase
{ {
private readonly IAuthService _authService; private readonly IAuthService _authService;

View File

@@ -15,16 +15,13 @@ namespace ThingsGateway.Admin.Application;
[Route("api/[controller]/[action]")] [Route("api/[controller]/[action]")]
[AllowAnonymous] [AllowAnonymous]
[ApiController]
public class TestController : ControllerBase public class TestController : ControllerBase
{ {
[HttpPost] [HttpGet]
public Task Test(string data) public void Test()
{ {
for (int i = 0; i < 3; i++) GC.Collect();
{ GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();
}
return Task.CompletedTask;
} }
} }

View File

@@ -22,26 +22,19 @@ using System.Globalization;
using System.Reflection; using System.Reflection;
using ThingsGateway.Extension; using ThingsGateway.Extension;
using ThingsGateway.SpecificationDocument;
namespace ThingsGateway.Admin.Application; namespace ThingsGateway.Admin.Application;
internal sealed class ApiPermissionService : IApiPermissionService internal sealed class ApiPermissionService : IApiPermissionService
{ {
private readonly IApiDescriptionGroupCollectionProvider _apiDescriptionGroupCollectionProvider; private readonly IApiDescriptionGroupCollectionProvider _apiDescriptionGroupCollectionProvider;
private readonly SwaggerGeneratorOptions _generatorOptions;
public ApiPermissionService( public ApiPermissionService(
IOptions<SwaggerGeneratorOptions> generatorOptions, IOptions<SwaggerGeneratorOptions> generatorOptions,
IApiDescriptionGroupCollectionProvider apiDescriptionGroupCollectionProvider) IApiDescriptionGroupCollectionProvider apiDescriptionGroupCollectionProvider)
{ {
_generatorOptions = generatorOptions.Value;
_apiDescriptionGroupCollectionProvider = apiDescriptionGroupCollectionProvider; _apiDescriptionGroupCollectionProvider = apiDescriptionGroupCollectionProvider;
} }
private IEnumerable<string> GetDocumentNames()
{
return _generatorOptions.SwaggerDocs.Keys;
}
/// <inheritdoc /> /// <inheritdoc />
public List<OpenApiPermissionTreeSelector> ApiPermissionTreeSelector() public List<OpenApiPermissionTreeSelector> ApiPermissionTreeSelector()
@@ -53,37 +46,37 @@ internal sealed class ApiPermissionService : IApiPermissionService
permissions = new(); permissions = new();
Dictionary<string, OpenApiPermissionTreeSelector> groupOpenApis = new(); Dictionary<string, OpenApiPermissionTreeSelector> groupOpenApis = new();
foreach (var item in GetDocumentNames())
{
OpenApiPermissionTreeSelector openApiPermissionTreeSelector = new() { ApiName = item ?? "Default" };
groupOpenApis.TryAdd(openApiPermissionTreeSelector.ApiName, openApiPermissionTreeSelector);
}
var apiDescriptions = _apiDescriptionGroupCollectionProvider.ApiDescriptionGroups.Items; var apiDescriptions = _apiDescriptionGroupCollectionProvider.ApiDescriptionGroups.Items;
foreach (var item1 in apiDescriptions)
{
foreach (var item in item1.Items)
{
if (item.ActionDescriptor is ControllerActionDescriptor controllerActionDescriptor)
{
OpenApiPermissionTreeSelector openApiPermissionTreeSelector = new() { ApiName = controllerActionDescriptor.ControllerName ?? "Default" };
groupOpenApis.TryAdd(openApiPermissionTreeSelector.ApiName, openApiPermissionTreeSelector);
}
}
}
// 获取所有需要数据权限的控制器 // 获取所有需要数据权限的控制器
var controllerTypes = var controllerTypes =
App.EffectiveTypes.Where(u => !u.IsInterface && !u.IsAbstract && u.IsClass && u.IsDefined(typeof(RolePermissionAttribute), false)); App.EffectiveTypes.Where(u => !u.IsInterface && !u.IsAbstract && u.IsClass && u.IsDefined(typeof(RolePermissionAttribute), false));
foreach (var groupOpenApi in groupOpenApis) //foreach (var groupOpenApi in groupOpenApis)
{ {
foreach (var apiDescriptionGroup in apiDescriptions) foreach (var apiDescriptionGroup in apiDescriptions)
{ {
var routes = apiDescriptionGroup.Items.Where(api => api.ActionDescriptor is ControllerActionDescriptor); var routes = apiDescriptionGroup.Items.Where(api => api.ActionDescriptor is ControllerActionDescriptor);
OpenApiPermissionTreeSelector openApiPermissionTreeSelector = groupOpenApi.Value;
Dictionary<string, OpenApiPermissionTreeSelector> openApiPermissionTreeSelectorDict = new(); Dictionary<string, OpenApiPermissionTreeSelector> openApiPermissionTreeSelectorDict = new();
foreach (var route in routes) foreach (var route in routes)
{ {
if (!SpecificationDocumentBuilder.CheckApiDescriptionInCurrentGroup(groupOpenApi.Key, route))
{
continue;
}
var actionDesc = (ControllerActionDescriptor)route.ActionDescriptor; var actionDesc = (ControllerActionDescriptor)route.ActionDescriptor;
if (!actionDesc.ControllerTypeInfo.CustomAttributes.Any(a => a.AttributeType == typeof(RolePermissionAttribute))) if (!actionDesc.ControllerTypeInfo.CustomAttributes.Any(a => a.AttributeType == typeof(RolePermissionAttribute)))
continue; continue;
@@ -116,10 +109,8 @@ internal sealed class ApiPermissionService : IApiPermissionService
} }
openApiPermissionTreeSelector.Children.AddRange(openApiPermissionTreeSelectorDict.Values); if (openApiPermissionTreeSelectorDict.Values.Any(a => a.Children.Count > 0))
permissions.AddRange(openApiPermissionTreeSelectorDict.Values);
if (openApiPermissionTreeSelector.Children.Any(a => a.Children.Count > 0))
permissions.Add(openApiPermissionTreeSelector);
} }

View File

@@ -21,7 +21,7 @@
<PackageReference Include="BootstrapBlazor.TableExport" Version="9.2.4" /> <PackageReference Include="BootstrapBlazor.TableExport" Version="9.2.4" />
<PackageReference Include="UAParser" Version="3.1.47" /> <PackageReference Include="UAParser" Version="3.1.47" />
<PackageReference Include="Rougamo.Fody" Version="5.0.0" /> <PackageReference Include="Rougamo.Fody" Version="5.0.0" />
<PackageReference Include="SqlSugarCore" Version="5.1.4.189" /> <PackageReference Include="SqlSugarCore" Version="5.1.4.193" />
</ItemGroup> </ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net8.0' "> <ItemGroup Condition=" '$(TargetFramework)' == 'net8.0' ">
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="8.0.1" /> <PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="8.0.1" />

View File

@@ -10,6 +10,9 @@
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Components.Authorization; using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption;
using Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel;
using Microsoft.AspNetCore.HttpOverrides; using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.AspNetCore.Mvc.Controllers; using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.StaticFiles; using Microsoft.AspNetCore.StaticFiles;
@@ -18,6 +21,7 @@ using Microsoft.Extensions.Options;
using Newtonsoft.Json; using Newtonsoft.Json;
using System.Security.Cryptography.X509Certificates;
using System.Text; using System.Text;
using System.Text.Encodings.Web; using System.Text.Encodings.Web;
using System.Text.Unicode; using System.Text.Unicode;
@@ -291,6 +295,21 @@ public class Startup : AppStartup
services.AddAuthorizationCore(); services.AddAuthorizationCore();
services.AddScoped<IAuthorizationHandler, BlazorServerAuthenticationHandler>(); services.AddScoped<IAuthorizationHandler, BlazorServerAuthenticationHandler>();
services.AddScoped<AuthenticationStateProvider, BlazorServerAuthenticationStateProvider>(); 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"> <None Update="pm2-linux.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None> </None>
<None Update="ThingsGateway.pfx">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="thingsgateway.service"> <None Update="thingsgateway.service">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None> </None>

Binary file not shown.

View File

@@ -7,7 +7,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="BootstrapBlazor.FontAwesome" Version="9.0.2" /> <PackageReference Include="BootstrapBlazor.FontAwesome" Version="9.0.2" />
<PackageReference Include="BootstrapBlazor" Version="9.5.12" /> <PackageReference Include="BootstrapBlazor" Version="9.6.1" />
<PackageReference Include="Yitter.IdGenerator" Version="1.0.14" /> <PackageReference Include="Yitter.IdGenerator" Version="1.0.14" />
</ItemGroup> </ItemGroup>

View File

@@ -1,8 +1,8 @@
<Project> <Project>
<PropertyGroup> <PropertyGroup>
<PluginVersion>10.5.9</PluginVersion> <PluginVersion>10.5.18</PluginVersion>
<ProPluginVersion>10.5.9</ProPluginVersion> <ProPluginVersion>10.5.18</ProPluginVersion>
<AuthenticationVersion>2.1.7</AuthenticationVersion> <AuthenticationVersion>2.1.7</AuthenticationVersion>
</PropertyGroup> </PropertyGroup>

View File

@@ -42,7 +42,10 @@ internal sealed class HeartbeatAndReceivePlugin : PluginBase, ITcpConnectedPlugi
set set
{ {
_heartbeat = value; _heartbeat = value;
HeartbeatByte = new ArraySegment<byte>(Encoding.UTF8.GetBytes(value)); if (!_heartbeat.IsNullOrEmpty())
{
HeartbeatByte = new ArraySegment<byte>(Encoding.UTF8.GetBytes(value));
}
} }
} }
private string _heartbeat; private string _heartbeat;
@@ -59,6 +62,8 @@ internal sealed class HeartbeatAndReceivePlugin : PluginBase, ITcpConnectedPlugi
return;//此处可判断,如果为服务器,则不用使用心跳。 return;//此处可判断,如果为服务器,则不用使用心跳。
} }
HeartbeatTime = Math.Max(HeartbeatTime, 1000);
if (DtuId.IsNullOrWhiteSpace()) return; if (DtuId.IsNullOrWhiteSpace()) return;
if (client is ITcpClient tcpClient) if (client is ITcpClient tcpClient)

View File

@@ -70,7 +70,7 @@ public static class PluginUtil
{ {
action += a => action += a =>
{ {
a.UseCheckClear() a.UseTcpSessionCheckClear()
.SetCheckClearType(CheckClearType.All) .SetCheckClearType(CheckClearType.All)
.SetTick(TimeSpan.FromMilliseconds(channelOptions.CheckClearTime)) .SetTick(TimeSpan.FromMilliseconds(channelOptions.CheckClearTime))
.SetOnClose(async (c, t) => .SetOnClose(async (c, t) =>

View File

@@ -562,7 +562,7 @@ public abstract class DeviceBase : DisposableObject, IDevice
finally finally
{ {
waitLock.Release(); waitLock.Release();
clientChannel.WaitHandlePool.Destroy(waitData); clientChannel.WaitHandlePool.Destroy(sign);
Channel.ChannelReceivedWaitDict.TryRemove(sign, out _); Channel.ChannelReceivedWaitDict.TryRemove(sign, out _);
} }
} }
@@ -960,7 +960,7 @@ public abstract class DeviceBase : DisposableObject, IDevice
if (tcpServiceChannel.TryGetClient($"ID={dtu.DtuId}", out var client)) if (tcpServiceChannel.TryGetClient($"ID={dtu.DtuId}", out var client))
{ {
client.WaitHandlePool?.SafeDispose(); client.WaitHandlePool?.SafeDispose();
client.Close(); _ = client.CloseAsync();
} }
} }

View File

@@ -150,6 +150,13 @@ public static class LoggerExtensions
logger.Log(TouchSocket.Core.LogLevel.Info, null, msg, null); logger.Log(TouchSocket.Core.LogLevel.Info, null, msg, null);
} }
/// <summary>
/// 输出提示日志
/// </summary>
public static void LogDebug(this ILog logger, string msg)
{
logger.Log(TouchSocket.Core.LogLevel.Debug, null, msg, null);
}
/// <summary> /// <summary>
/// 输出Trace日志 /// 输出Trace日志
/// </summary> /// </summary>

View File

@@ -10,8 +10,8 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.Extensions.Localization.Abstractions" Version="9.0.4" /> <PackageReference Include="Microsoft.Extensions.Localization.Abstractions" Version="9.0.4" />
<PackageReference Include="TouchSocket" Version="3.1.0" /> <PackageReference Include="TouchSocket" Version="3.1.2" />
<PackageReference Include="TouchSocket.SerialPorts" Version="3.1.0" /> <PackageReference Include="TouchSocket.SerialPorts" Version="3.1.2" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

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

View File

@@ -36,6 +36,7 @@ namespace ThingsGateway.Gateway.Application;
[Route("openApi/control")] [Route("openApi/control")]
[RolePermission] [RolePermission]
[LoggingMonitor] [LoggingMonitor]
[ApiController]
[Authorize(AuthenticationSchemes = "Bearer")] [Authorize(AuthenticationSchemes = "Bearer")]
public class ControlController : ControllerBase public class ControlController : ControllerBase
{ {

View File

@@ -24,6 +24,7 @@ namespace ThingsGateway.Gateway.Application;
[ApiDescriptionSettings("ThingsGateway.OpenApi", Order = 200)] [ApiDescriptionSettings("ThingsGateway.OpenApi", Order = 200)]
[DisplayName("数据状态")] [DisplayName("数据状态")]
[Route("openApi/runtimeInfo")] [Route("openApi/runtimeInfo")]
[ApiController]
[RolePermission] [RolePermission]
[Authorize(AuthenticationSchemes = "Bearer")] [Authorize(AuthenticationSchemes = "Bearer")]
public class RuntimeInfoController : ControllerBase public class RuntimeInfoController : ControllerBase

View File

@@ -35,6 +35,7 @@ public abstract class BusinessBaseWithCacheAlarmModel<VarModel, DevModel, AlarmM
{ {
try try
{ {
LogMessage?.LogInformation($"Add {typeof(DevModel).Name} data to file cache, count {data.Count}");
foreach (var item in data) foreach (var item in data)
{ {
item.Id = CommonUtils.GetSingleId(); item.Id = CommonUtils.GetSingleId();
@@ -100,6 +101,7 @@ public abstract class BusinessBaseWithCacheAlarmModel<VarModel, DevModel, AlarmM
{ {
if (_memoryAlarmModelQueue.Count > _businessPropertyWithCache.QueueMaxCount) if (_memoryAlarmModelQueue.Count > _businessPropertyWithCache.QueueMaxCount)
{ {
LogMessage?.LogWarning($"{typeof(AlarmModel).Name} Queue exceeds limit, clear old data. If it doesn't work as expected, increase [QueueMaxCount] or Enable cache");
_memoryAlarmModelQueue.Clear(); _memoryAlarmModelQueue.Clear();
_memoryAlarmModelQueue.Enqueue(data); _memoryAlarmModelQueue.Enqueue(data);
return; return;

View File

@@ -36,6 +36,7 @@ public abstract class BusinessBaseWithCacheDeviceModel<VarModel, DevModel> : Bus
try try
{ {
LogMessage?.LogInformation($"Add {typeof(DevModel).Name} data to file cache, count {data.Count}");
foreach (var item in data) foreach (var item in data)
{ {
item.Id = CommonUtils.GetSingleId(); item.Id = CommonUtils.GetSingleId();
@@ -101,6 +102,7 @@ public abstract class BusinessBaseWithCacheDeviceModel<VarModel, DevModel> : Bus
{ {
if (_memoryDevModelQueue.Count > _businessPropertyWithCache.QueueMaxCount) if (_memoryDevModelQueue.Count > _businessPropertyWithCache.QueueMaxCount)
{ {
LogMessage?.LogWarning($"{typeof(DevModel).Name} Queue exceeds limit, clear old data. If it doesn't work as expected, increase [QueueMaxCount] or Enable cache");
_memoryDevModelQueue.Clear(); _memoryDevModelQueue.Clear();
_memoryDevModelQueue.Enqueue(data); _memoryDevModelQueue.Enqueue(data);
return; return;

View File

@@ -39,6 +39,7 @@ public abstract class BusinessBaseWithCacheVariableModel<VarModel> : BusinessBas
{ {
try try
{ {
LogMessage?.LogInformation($"Add {typeof(VarModel).Name} data to file cache, count {data.Count}");
foreach (var item in data) foreach (var item in data)
{ {
item.Id = CommonUtils.GetSingleId(); item.Id = CommonUtils.GetSingleId();
@@ -147,6 +148,7 @@ public abstract class BusinessBaseWithCacheVariableModel<VarModel> : BusinessBas
{ {
if (_memoryVarModelQueue.Count > _businessPropertyWithCache.QueueMaxCount) if (_memoryVarModelQueue.Count > _businessPropertyWithCache.QueueMaxCount)
{ {
LogMessage?.LogWarning($"{typeof(VarModel).Name} Queue exceeds limit, clear old data. If it doesn't work as expected, increase [QueueMaxCount] or Enable cache");
_memoryVarModelQueue.Clear(); _memoryVarModelQueue.Clear();
_memoryVarModelQueue.Enqueue(data); _memoryVarModelQueue.Enqueue(data);
return; return;

View File

@@ -162,6 +162,8 @@ public abstract class BusinessBaseWithCacheIntervalAlarmModel<VarModel, DevModel
{ {
if (_exTTimerTick.IsTickHappen()) if (_exTTimerTick.IsTickHappen())
{ {
if (LogMessage.LogLevel <= LogLevel.Debug)
LogMessage?.LogDebug($"Interval {typeof(VarModel).Name} data, count {IdVariableRuntimes.Count}");
// 间隔推送全部变量 // 间隔推送全部变量
var variableRuntimes = IdVariableRuntimes.Select(a => a.Value); var variableRuntimes = IdVariableRuntimes.Select(a => a.Value);
VariableTimeInterval(variableRuntimes, variableRuntimes.Adapt<List<VariableBasicData>>()); VariableTimeInterval(variableRuntimes, variableRuntimes.Adapt<List<VariableBasicData>>());
@@ -177,6 +179,8 @@ public abstract class BusinessBaseWithCacheIntervalAlarmModel<VarModel, DevModel
{ {
if (CollectDevices != null) if (CollectDevices != null)
{ {
if (LogMessage.LogLevel <= LogLevel.Debug)
LogMessage?.LogDebug($"Interval {typeof(DevModel).Name} data, count {CollectDevices.Count}");
// 间隔推送全部设备 // 间隔推送全部设备
foreach (var deviceRuntime in CollectDevices.Select(a => a.Value)) foreach (var deviceRuntime in CollectDevices.Select(a => a.Value))

View File

@@ -152,6 +152,8 @@ public abstract class BusinessBaseWithCacheIntervalDeviceModel<VarModel, DevMode
{ {
if (_exTTimerTick.IsTickHappen()) if (_exTTimerTick.IsTickHappen())
{ {
if (LogMessage.LogLevel <= LogLevel.Debug)
LogMessage?.LogDebug($"Interval {typeof(VarModel).Name} data, count {IdVariableRuntimes.Count}");
// 上传所有变量信息 // 上传所有变量信息
var variableRuntimes = IdVariableRuntimes.Select(a => a.Value); var variableRuntimes = IdVariableRuntimes.Select(a => a.Value);
VariableTimeInterval(variableRuntimes, variableRuntimes.Adapt<List<VariableBasicData>>()); VariableTimeInterval(variableRuntimes, variableRuntimes.Adapt<List<VariableBasicData>>());
@@ -168,6 +170,8 @@ public abstract class BusinessBaseWithCacheIntervalDeviceModel<VarModel, DevMode
{ {
if (CollectDevices != null) if (CollectDevices != null)
{ {
if (LogMessage.LogLevel <= LogLevel.Debug)
LogMessage?.LogDebug($"Interval {typeof(DevModel).Name} data, count {CollectDevices.Count}");
// 上传所有设备信息 // 上传所有设备信息
foreach (var deviceRuntime in CollectDevices.Select(a => a.Value)) foreach (var deviceRuntime in CollectDevices.Select(a => a.Value))
{ {

View File

@@ -40,7 +40,7 @@ public abstract partial class BusinessBaseWithCacheIntervalScript<VarModel, DevM
List<string> strings = new List<string>(); List<string> strings = new List<string>();
// 使用正则表达式查找输入字符串中的所有匹配项 // 使用正则表达式查找输入字符串中的所有匹配项
Regex regex = new Regex(@"\$\{(.+?)\}"); Regex regex = TopicRegex();
MatchCollection matches = regex.Matches(input); MatchCollection matches = regex.Matches(input);
// 遍历匹配结果,将匹配到的字符串添加到列表中 // 遍历匹配结果,将匹配到的字符串添加到列表中
@@ -89,10 +89,12 @@ public abstract partial class BusinessBaseWithCacheIntervalScript<VarModel, DevM
// 上传内容 // 上传内容
if (_businessPropertyWithCacheIntervalScript.IsAlarmList) if (_businessPropertyWithCacheIntervalScript.IsAlarmList)
{ {
// 如果是报警列表,则将整个分组转换为 JSON 字符串 // 如果是报警列表,则将整个分组转换为 JSON 字符串
string json = group.Select(a => a).ToList().ToJsonNetString(_businessPropertyWithCacheIntervalScript.JsonFormattingIndented); var gList = group.Select(a => a).ToList();
string json = gList.ToJsonNetString(_businessPropertyWithCacheIntervalScript.JsonFormattingIndented);
// 将主题和 JSON 内容添加到列表中 // 将主题和 JSON 内容添加到列表中
topicJsonList.Add(new(topic, json)); topicJsonList.Add(new(topic, json, gList.Count));
} }
else else
{ {
@@ -101,7 +103,7 @@ public abstract partial class BusinessBaseWithCacheIntervalScript<VarModel, DevM
{ {
string json = JsonExtensions.ToJsonNetString(gro, _businessPropertyWithCacheIntervalScript.JsonFormattingIndented); string json = JsonExtensions.ToJsonNetString(gro, _businessPropertyWithCacheIntervalScript.JsonFormattingIndented);
// 将主题和 JSON 内容添加到列表中 // 将主题和 JSON 内容添加到列表中
topicJsonList.Add(new(topic, json)); topicJsonList.Add(new(topic, json, 1));
} }
} }
} }
@@ -111,15 +113,16 @@ public abstract partial class BusinessBaseWithCacheIntervalScript<VarModel, DevM
{ {
if (_businessPropertyWithCacheIntervalScript.IsAlarmList) if (_businessPropertyWithCacheIntervalScript.IsAlarmList)
{ {
string json = data.Select(a => a).ToList().ToJsonNetString(_businessPropertyWithCacheIntervalScript.JsonFormattingIndented); var gList = data.Select(a => a).ToList();
topicJsonList.Add(new(_businessPropertyWithCacheIntervalScript.AlarmTopic, json)); string json = gList.ToJsonNetString(_businessPropertyWithCacheIntervalScript.JsonFormattingIndented);
topicJsonList.Add(new(_businessPropertyWithCacheIntervalScript.AlarmTopic, json, gList.Count));
} }
else else
{ {
foreach (var group in data) foreach (var group in data)
{ {
string json = JsonExtensions.ToJsonNetString(group, _businessPropertyWithCacheIntervalScript.JsonFormattingIndented); string json = JsonExtensions.ToJsonNetString(group, _businessPropertyWithCacheIntervalScript.JsonFormattingIndented);
topicJsonList.Add(new(_businessPropertyWithCacheIntervalScript.AlarmTopic, json)); topicJsonList.Add(new(_businessPropertyWithCacheIntervalScript.AlarmTopic, json, 1));
} }
} }
} }
@@ -156,9 +159,10 @@ public abstract partial class BusinessBaseWithCacheIntervalScript<VarModel, DevM
if (_businessPropertyWithCacheIntervalScript.IsDeviceList) if (_businessPropertyWithCacheIntervalScript.IsDeviceList)
{ {
// 如果是设备列表,则将整个分组转换为 JSON 字符串 // 如果是设备列表,则将整个分组转换为 JSON 字符串
string json = group.Select(a => a).ToList().ToJsonNetString(_businessPropertyWithCacheIntervalScript.JsonFormattingIndented); var gList = group.Select(a => a).ToList();
string json = gList.ToJsonNetString(_businessPropertyWithCacheIntervalScript.JsonFormattingIndented);
// 将主题和 JSON 内容添加到列表中 // 将主题和 JSON 内容添加到列表中
topicJsonList.Add(new(topic, json)); topicJsonList.Add(new(topic, json, gList.Count));
} }
else else
{ {
@@ -167,7 +171,7 @@ public abstract partial class BusinessBaseWithCacheIntervalScript<VarModel, DevM
{ {
string json = JsonExtensions.ToJsonNetString(gro, _businessPropertyWithCacheIntervalScript.JsonFormattingIndented); string json = JsonExtensions.ToJsonNetString(gro, _businessPropertyWithCacheIntervalScript.JsonFormattingIndented);
// 将主题和 JSON 内容添加到列表中 // 将主题和 JSON 内容添加到列表中
topicJsonList.Add(new(topic, json)); topicJsonList.Add(new(topic, json, 1));
} }
} }
} }
@@ -178,15 +182,16 @@ public abstract partial class BusinessBaseWithCacheIntervalScript<VarModel, DevM
{ {
if (_businessPropertyWithCacheIntervalScript.IsDeviceList) if (_businessPropertyWithCacheIntervalScript.IsDeviceList)
{ {
string json = data.Select(a => a).ToList().ToJsonNetString(_businessPropertyWithCacheIntervalScript.JsonFormattingIndented); var gList = data.Select(a => a).ToList();
topicJsonList.Add(new(_businessPropertyWithCacheIntervalScript.DeviceTopic, json)); string json = gList.ToJsonNetString(_businessPropertyWithCacheIntervalScript.JsonFormattingIndented);
topicJsonList.Add(new(_businessPropertyWithCacheIntervalScript.DeviceTopic, json, gList.Count));
} }
else else
{ {
foreach (var group in data) foreach (var group in data)
{ {
string json = JsonExtensions.ToJsonNetString(group, _businessPropertyWithCacheIntervalScript.JsonFormattingIndented); string json = JsonExtensions.ToJsonNetString(group, _businessPropertyWithCacheIntervalScript.JsonFormattingIndented);
topicJsonList.Add(new(_businessPropertyWithCacheIntervalScript.DeviceTopic, json)); topicJsonList.Add(new(_businessPropertyWithCacheIntervalScript.DeviceTopic, json, 1));
} }
} }
} }
@@ -221,9 +226,10 @@ public abstract partial class BusinessBaseWithCacheIntervalScript<VarModel, DevM
if (_businessPropertyWithCacheIntervalScript.IsVariableList) if (_businessPropertyWithCacheIntervalScript.IsVariableList)
{ {
// 如果是变量列表,则将整个分组转换为 JSON 字符串 // 如果是变量列表,则将整个分组转换为 JSON 字符串
string json = group.Select(a => a).ToList().ToJsonNetString(_businessPropertyWithCacheIntervalScript.JsonFormattingIndented); var gList = group.Select(a => a).ToList();
string json = gList.ToJsonNetString(_businessPropertyWithCacheIntervalScript.JsonFormattingIndented);
// 将主题和 JSON 内容添加到列表中 // 将主题和 JSON 内容添加到列表中
topicJsonList.Add(new(topic, json)); topicJsonList.Add(new(topic, json, gList.Count));
} }
else else
{ {
@@ -232,7 +238,7 @@ public abstract partial class BusinessBaseWithCacheIntervalScript<VarModel, DevM
{ {
string json = JsonExtensions.ToJsonNetString(gro, _businessPropertyWithCacheIntervalScript.JsonFormattingIndented); string json = JsonExtensions.ToJsonNetString(gro, _businessPropertyWithCacheIntervalScript.JsonFormattingIndented);
// 将主题和 JSON 内容添加到列表中 // 将主题和 JSON 内容添加到列表中
topicJsonList.Add(new(topic, json)); topicJsonList.Add(new(topic, json, 1));
} }
} }
} }
@@ -243,15 +249,16 @@ public abstract partial class BusinessBaseWithCacheIntervalScript<VarModel, DevM
{ {
if (_businessPropertyWithCacheIntervalScript.IsVariableList) if (_businessPropertyWithCacheIntervalScript.IsVariableList)
{ {
string json = data.Select(a => a).ToList().ToJsonNetString(_businessPropertyWithCacheIntervalScript.JsonFormattingIndented); var gList = data.Select(a => a).ToList();
topicJsonList.Add(new(_businessPropertyWithCacheIntervalScript.VariableTopic, json)); string json = gList.ToJsonNetString(_businessPropertyWithCacheIntervalScript.JsonFormattingIndented);
topicJsonList.Add(new(_businessPropertyWithCacheIntervalScript.VariableTopic, json, gList.Count));
} }
else else
{ {
foreach (var group in data) foreach (var group in data)
{ {
string json = JsonExtensions.ToJsonNetString(group, _businessPropertyWithCacheIntervalScript.JsonFormattingIndented); string json = JsonExtensions.ToJsonNetString(group, _businessPropertyWithCacheIntervalScript.JsonFormattingIndented);
topicJsonList.Add(new(_businessPropertyWithCacheIntervalScript.VariableTopic, json)); topicJsonList.Add(new(_businessPropertyWithCacheIntervalScript.VariableTopic, json, 1));
} }
} }
} }
@@ -294,10 +301,11 @@ public abstract partial class BusinessBaseWithCacheIntervalScript<VarModel, DevM
// 上传内容 // 上传内容
if (_businessPropertyWithCacheIntervalScript.IsVariableList) if (_businessPropertyWithCacheIntervalScript.IsVariableList)
{ {
// 如果是变量列表,则将整个分组转换为 JSON 字符串 // 如果是变量列表,则将整个分组转换为 JSON 字符串
string json = group.Select(a => a).GroupBy(a => a.DeviceName, b => b).ToDictionary(a => a.Key, b => b.ToList()).ToJsonNetString(_businessPropertyWithCacheIntervalScript.JsonFormattingIndented); string json = group.Select(a => a).GroupBy(a => a.DeviceName, b => b).ToDictionary(a => a.Key, b => b.ToList()).ToJsonNetString(_businessPropertyWithCacheIntervalScript.JsonFormattingIndented);
// 将主题和 JSON 内容添加到列表中 // 将主题和 JSON 内容添加到列表中
topicJsonList.Add(new(topic, json)); topicJsonList.Add(new(topic, json, group.Count()));
} }
else else
{ {
@@ -306,7 +314,7 @@ public abstract partial class BusinessBaseWithCacheIntervalScript<VarModel, DevM
{ {
string json = JsonExtensions.ToJsonNetString(gro, _businessPropertyWithCacheIntervalScript.JsonFormattingIndented); string json = JsonExtensions.ToJsonNetString(gro, _businessPropertyWithCacheIntervalScript.JsonFormattingIndented);
// 将主题和 JSON 内容添加到列表中 // 将主题和 JSON 内容添加到列表中
topicJsonList.Add(new(topic, json)); topicJsonList.Add(new(topic, json, 1));
} }
} }
} }
@@ -318,14 +326,14 @@ public abstract partial class BusinessBaseWithCacheIntervalScript<VarModel, DevM
if (_businessPropertyWithCacheIntervalScript.IsVariableList) if (_businessPropertyWithCacheIntervalScript.IsVariableList)
{ {
string json = data.Select(a => a).GroupBy(a => a.DeviceName, b => b).ToDictionary(a => a.Key, b => b.ToList()).ToJsonNetString(_businessPropertyWithCacheIntervalScript.JsonFormattingIndented); string json = data.Select(a => a).GroupBy(a => a.DeviceName, b => b).ToDictionary(a => a.Key, b => b.ToList()).ToJsonNetString(_businessPropertyWithCacheIntervalScript.JsonFormattingIndented);
topicJsonList.Add(new(_businessPropertyWithCacheIntervalScript.VariableTopic, json)); topicJsonList.Add(new(_businessPropertyWithCacheIntervalScript.VariableTopic, json, data.Count()));
} }
else else
{ {
foreach (var group in data) foreach (var group in data)
{ {
string json = JsonExtensions.ToJsonNetString(group, _businessPropertyWithCacheIntervalScript.JsonFormattingIndented); string json = JsonExtensions.ToJsonNetString(group, _businessPropertyWithCacheIntervalScript.JsonFormattingIndented);
topicJsonList.Add(new(_businessPropertyWithCacheIntervalScript.VariableTopic, json)); topicJsonList.Add(new(_businessPropertyWithCacheIntervalScript.VariableTopic, json, 1));
} }
} }
} }
@@ -369,7 +377,7 @@ public abstract partial class BusinessBaseWithCacheIntervalScript<VarModel, DevM
protected List<TopicArray> GetAlarmTopicArrays(IEnumerable<AlarmModel> item) protected List<TopicArray> GetAlarmTopicArrays(IEnumerable<AlarmModel> item)
{ {
IEnumerable<dynamic>? data = Application.DynamicModelExtension.GetDynamicModel<AlarmModel>(item, _businessPropertyWithCacheIntervalScript.BigTextScriptAlarmModel); IEnumerable<dynamic>? data = Application.DynamicModelExtension.GetDynamicModel<AlarmModel>(item, _businessPropertyWithCacheIntervalScript.BigTextScriptAlarmModel);
List<TopicArray> topicJsonList = new List<TopicArray>(); List<TopicArray> topicArrayList = new List<TopicArray>();
var topics = Match(_businessPropertyWithCacheIntervalScript.AlarmTopic); var topics = Match(_businessPropertyWithCacheIntervalScript.AlarmTopic);
if (topics.Count > 0) if (topics.Count > 0)
{ {
@@ -392,9 +400,10 @@ public abstract partial class BusinessBaseWithCacheIntervalScript<VarModel, DevM
// 上传内容 // 上传内容
if (_businessPropertyWithCacheIntervalScript.IsAlarmList) if (_businessPropertyWithCacheIntervalScript.IsAlarmList)
{ {
var json = Serialize(group.Select(a => a).ToList().ToList(), _businessPropertyWithCacheIntervalScript.JsonFormattingIndented); var gList = group.Select(a => a).ToList();
var json = Serialize(gList, _businessPropertyWithCacheIntervalScript.JsonFormattingIndented);
// 将主题和 JSON 内容添加到列表中 // 将主题和 JSON 内容添加到列表中
topicJsonList.Add(new(topic, json)); topicArrayList.Add(new(topic, json, gList.Count));
} }
else else
{ {
@@ -403,7 +412,7 @@ public abstract partial class BusinessBaseWithCacheIntervalScript<VarModel, DevM
{ {
var json = Serialize(gro, _businessPropertyWithCacheIntervalScript.JsonFormattingIndented); var json = Serialize(gro, _businessPropertyWithCacheIntervalScript.JsonFormattingIndented);
// 将主题和 JSON 内容添加到列表中 // 将主题和 JSON 内容添加到列表中
topicJsonList.Add(new(topic, json)); topicArrayList.Add(new(topic, json, 1));
} }
} }
} }
@@ -413,26 +422,27 @@ public abstract partial class BusinessBaseWithCacheIntervalScript<VarModel, DevM
{ {
if (_businessPropertyWithCacheIntervalScript.IsAlarmList) if (_businessPropertyWithCacheIntervalScript.IsAlarmList)
{ {
var json = Serialize(data.Select(a => a).ToList(), _businessPropertyWithCacheIntervalScript.JsonFormattingIndented); var gList = data.Select(a => a).ToList();
topicJsonList.Add(new(_businessPropertyWithCacheIntervalScript.AlarmTopic, json)); var json = Serialize(gList, _businessPropertyWithCacheIntervalScript.JsonFormattingIndented);
topicArrayList.Add(new(_businessPropertyWithCacheIntervalScript.AlarmTopic, json, gList.Count));
} }
else else
{ {
foreach (var group in data) foreach (var group in data)
{ {
var json = Serialize(group, _businessPropertyWithCacheIntervalScript.JsonFormattingIndented); var json = Serialize(group, _businessPropertyWithCacheIntervalScript.JsonFormattingIndented);
topicJsonList.Add(new(_businessPropertyWithCacheIntervalScript.AlarmTopic, json)); topicArrayList.Add(new(_businessPropertyWithCacheIntervalScript.AlarmTopic, json, 1));
} }
} }
} }
return topicJsonList; return topicArrayList;
} }
protected List<TopicArray> GetDeviceTopicArray(IEnumerable<DevModel> item) protected List<TopicArray> GetDeviceTopicArray(IEnumerable<DevModel> item)
{ {
IEnumerable<dynamic>? data = Application.DynamicModelExtension.GetDynamicModel<DevModel>(item, _businessPropertyWithCacheIntervalScript.BigTextScriptDeviceModel); IEnumerable<dynamic>? data = Application.DynamicModelExtension.GetDynamicModel<DevModel>(item, _businessPropertyWithCacheIntervalScript.BigTextScriptDeviceModel);
List<TopicArray> topicJsonList = new List<TopicArray>(); List<TopicArray> topicArrayList = new List<TopicArray>();
var topics = Match(_businessPropertyWithCacheIntervalScript.DeviceTopic); var topics = Match(_businessPropertyWithCacheIntervalScript.DeviceTopic);
if (topics.Count > 0) if (topics.Count > 0)
{ {
@@ -457,9 +467,10 @@ public abstract partial class BusinessBaseWithCacheIntervalScript<VarModel, DevM
if (_businessPropertyWithCacheIntervalScript.IsDeviceList) if (_businessPropertyWithCacheIntervalScript.IsDeviceList)
{ {
// 如果是设备列表,则将整个分组转换为 JSON 字符串 // 如果是设备列表,则将整个分组转换为 JSON 字符串
var json = Serialize(group.Select(a => a).ToList(), _businessPropertyWithCacheIntervalScript.JsonFormattingIndented); var gList = group.Select(a => a).ToList();
var json = Serialize(gList, _businessPropertyWithCacheIntervalScript.JsonFormattingIndented);
// 将主题和 JSON 内容添加到列表中 // 将主题和 JSON 内容添加到列表中
topicJsonList.Add(new(topic, json)); topicArrayList.Add(new(topic, json, gList.Count));
} }
else else
{ {
@@ -468,7 +479,7 @@ public abstract partial class BusinessBaseWithCacheIntervalScript<VarModel, DevM
{ {
var json = Serialize(gro, _businessPropertyWithCacheIntervalScript.JsonFormattingIndented); var json = Serialize(gro, _businessPropertyWithCacheIntervalScript.JsonFormattingIndented);
// 将主题和 JSON 内容添加到列表中 // 将主题和 JSON 内容添加到列表中
topicJsonList.Add(new(topic, json)); topicArrayList.Add(new(topic, json, 1));
} }
} }
} }
@@ -479,25 +490,26 @@ public abstract partial class BusinessBaseWithCacheIntervalScript<VarModel, DevM
{ {
if (_businessPropertyWithCacheIntervalScript.IsDeviceList) if (_businessPropertyWithCacheIntervalScript.IsDeviceList)
{ {
var json = Serialize(data.Select(a => a).ToList(), _businessPropertyWithCacheIntervalScript.JsonFormattingIndented); var gList = data.Select(a => a).ToList();
topicJsonList.Add(new(_businessPropertyWithCacheIntervalScript.DeviceTopic, json)); var json = Serialize(gList, _businessPropertyWithCacheIntervalScript.JsonFormattingIndented);
topicArrayList.Add(new(_businessPropertyWithCacheIntervalScript.DeviceTopic, json, gList.Count));
} }
else else
{ {
foreach (var group in data) foreach (var group in data)
{ {
var json = Serialize(group, _businessPropertyWithCacheIntervalScript.JsonFormattingIndented); var json = Serialize(group, _businessPropertyWithCacheIntervalScript.JsonFormattingIndented);
topicJsonList.Add(new(_businessPropertyWithCacheIntervalScript.DeviceTopic, json)); topicArrayList.Add(new(_businessPropertyWithCacheIntervalScript.DeviceTopic, json, 1));
} }
} }
} }
return topicJsonList; return topicArrayList;
} }
protected List<TopicArray> GetVariableTopicArray(IEnumerable<VarModel> item) protected List<TopicArray> GetVariableTopicArray(IEnumerable<VarModel> item)
{ {
IEnumerable<dynamic>? data = Application.DynamicModelExtension.GetDynamicModel<VarModel>(item, _businessPropertyWithCacheIntervalScript.BigTextScriptVariableModel); IEnumerable<dynamic>? data = Application.DynamicModelExtension.GetDynamicModel<VarModel>(item, _businessPropertyWithCacheIntervalScript.BigTextScriptVariableModel);
List<TopicArray> topicJsonList = new List<TopicArray>(); List<TopicArray> topicArrayList = new List<TopicArray>();
var topics = Match(_businessPropertyWithCacheIntervalScript.VariableTopic); var topics = Match(_businessPropertyWithCacheIntervalScript.VariableTopic);
if (topics.Count > 0) if (topics.Count > 0)
{ {
@@ -522,9 +534,10 @@ public abstract partial class BusinessBaseWithCacheIntervalScript<VarModel, DevM
if (_businessPropertyWithCacheIntervalScript.IsVariableList) if (_businessPropertyWithCacheIntervalScript.IsVariableList)
{ {
// 如果是变量列表,则将整个分组转换为 JSON 字符串 // 如果是变量列表,则将整个分组转换为 JSON 字符串
var json = Serialize(group.Select(a => a).ToList(), _businessPropertyWithCacheIntervalScript.JsonFormattingIndented); var gList = group.Select(a => a).ToList();
var json = Serialize(gList, _businessPropertyWithCacheIntervalScript.JsonFormattingIndented);
// 将主题和 JSON 内容添加到列表中 // 将主题和 JSON 内容添加到列表中
topicJsonList.Add(new(topic, json)); topicArrayList.Add(new(topic, json, gList.Count));
} }
else else
{ {
@@ -533,7 +546,7 @@ public abstract partial class BusinessBaseWithCacheIntervalScript<VarModel, DevM
{ {
var json = Serialize(gro, _businessPropertyWithCacheIntervalScript.JsonFormattingIndented); var json = Serialize(gro, _businessPropertyWithCacheIntervalScript.JsonFormattingIndented);
// 将主题和 JSON 内容添加到列表中 // 将主题和 JSON 内容添加到列表中
topicJsonList.Add(new(topic, json)); topicArrayList.Add(new(topic, json, 1));
} }
} }
} }
@@ -544,19 +557,20 @@ public abstract partial class BusinessBaseWithCacheIntervalScript<VarModel, DevM
{ {
if (_businessPropertyWithCacheIntervalScript.IsVariableList) if (_businessPropertyWithCacheIntervalScript.IsVariableList)
{ {
var json = Serialize(data.Select(a => a).ToList(), _businessPropertyWithCacheIntervalScript.JsonFormattingIndented); var gList = data.Select(a => a).ToList();
topicJsonList.Add(new(_businessPropertyWithCacheIntervalScript.VariableTopic, json)); var json = Serialize(gList, _businessPropertyWithCacheIntervalScript.JsonFormattingIndented);
topicArrayList.Add(new(_businessPropertyWithCacheIntervalScript.VariableTopic, json, gList.Count));
} }
else else
{ {
foreach (var group in data) foreach (var group in data)
{ {
var json = Serialize(group, _businessPropertyWithCacheIntervalScript.JsonFormattingIndented); var json = Serialize(group, _businessPropertyWithCacheIntervalScript.JsonFormattingIndented);
topicJsonList.Add(new(_businessPropertyWithCacheIntervalScript.VariableTopic, json)); topicArrayList.Add(new(_businessPropertyWithCacheIntervalScript.VariableTopic, json, 1));
} }
} }
} }
return topicJsonList; return topicArrayList;
} }
protected List<TopicArray> GetVariableBasicDataTopicArray(IEnumerable<VariableBasicData> item) protected List<TopicArray> GetVariableBasicDataTopicArray(IEnumerable<VariableBasicData> item)
@@ -571,7 +585,7 @@ public abstract partial class BusinessBaseWithCacheIntervalScript<VarModel, DevM
data = item; data = item;
} }
List<TopicArray> topicJsonList = new List<TopicArray>(); List<TopicArray> topicArrayList = new List<TopicArray>();
var topics = Match(_businessPropertyWithCacheIntervalScript.VariableTopic); var topics = Match(_businessPropertyWithCacheIntervalScript.VariableTopic);
if (topics.Count > 0) if (topics.Count > 0)
{ {
@@ -596,9 +610,10 @@ public abstract partial class BusinessBaseWithCacheIntervalScript<VarModel, DevM
if (_businessPropertyWithCacheIntervalScript.IsVariableList) if (_businessPropertyWithCacheIntervalScript.IsVariableList)
{ {
// 如果是变量列表,则将整个分组转换为 JSON 字符串 // 如果是变量列表,则将整个分组转换为 JSON 字符串
var json = Serialize(group.Select(a => a).ToList(), _businessPropertyWithCacheIntervalScript.JsonFormattingIndented); var gList = group.Select(a => a).ToList();
var json = Serialize(gList, _businessPropertyWithCacheIntervalScript.JsonFormattingIndented);
// 将主题和 JSON 内容添加到列表中 // 将主题和 JSON 内容添加到列表中
topicJsonList.Add(new(topic, json)); topicArrayList.Add(new(topic, json, gList.Count));
} }
else else
{ {
@@ -607,7 +622,7 @@ public abstract partial class BusinessBaseWithCacheIntervalScript<VarModel, DevM
{ {
var json = Serialize(gro, _businessPropertyWithCacheIntervalScript.JsonFormattingIndented); var json = Serialize(gro, _businessPropertyWithCacheIntervalScript.JsonFormattingIndented);
// 将主题和 JSON 内容添加到列表中 // 将主题和 JSON 内容添加到列表中
topicJsonList.Add(new(topic, json)); topicArrayList.Add(new(topic, json, 1));
} }
} }
} }
@@ -618,25 +633,40 @@ public abstract partial class BusinessBaseWithCacheIntervalScript<VarModel, DevM
{ {
if (_businessPropertyWithCacheIntervalScript.IsVariableList) if (_businessPropertyWithCacheIntervalScript.IsVariableList)
{ {
var json = Serialize(data.Select(a => a).ToList(), _businessPropertyWithCacheIntervalScript.JsonFormattingIndented); var gList = data.Select(a => a).ToList();
topicJsonList.Add(new(_businessPropertyWithCacheIntervalScript.VariableTopic, json)); var json = Serialize(gList, _businessPropertyWithCacheIntervalScript.JsonFormattingIndented);
topicArrayList.Add(new(_businessPropertyWithCacheIntervalScript.VariableTopic, json, gList.Count));
} }
else else
{ {
foreach (var group in data) foreach (var group in data)
{ {
var json = Serialize(group, _businessPropertyWithCacheIntervalScript.JsonFormattingIndented); var json = Serialize(group, _businessPropertyWithCacheIntervalScript.JsonFormattingIndented);
topicJsonList.Add(new(_businessPropertyWithCacheIntervalScript.VariableTopic, json)); topicArrayList.Add(new(_businessPropertyWithCacheIntervalScript.VariableTopic, json, 1));
} }
} }
} }
return topicJsonList; return topicArrayList;
} }
protected string GetString(string topic, byte[] json, int count) protected string GetDetailLogString(TopicArray topicArray, int queueCount)
{ {
return $"Topic{topic}{Environment.NewLine}PayLoad{Encoding.UTF8.GetString(json)} {Environment.NewLine} VarModelQueue:{count}"; if (queueCount > 0)
return $"Up Topic{topicArray.Topic}{Environment.NewLine}PayLoad{Encoding.UTF8.GetString(topicArray.Json)} {Environment.NewLine} VarModelQueue:{queueCount}";
else
return $"Up Topic{topicArray.Topic}{Environment.NewLine}PayLoad{Encoding.UTF8.GetString(topicArray.Json)}";
} }
protected string GetCountLogString(TopicArray topicArray, int queueCount)
{
if (queueCount > 0)
return $"Up Topic{topicArray.Topic}{Environment.NewLine}Count{topicArray.Count} {Environment.NewLine} VarModelQueue:{queueCount}";
else
return $"Up Topic{topicArray.Topic}{Environment.NewLine}Count{topicArray.Count}";
}
[GeneratedRegex(@"\$\{(.+?)\}")]
private static partial Regex TopicRegex();
#endregion #endregion
} }

View File

@@ -18,10 +18,10 @@ using TouchSocket.Core;
namespace ThingsGateway.Gateway.Application; namespace ThingsGateway.Gateway.Application;
/// <summary> /// <summary>
/// 抽象类 <see cref="BusinessBaseWithCacheIntervalVariableModel{T}"/>,表示具有缓存间隔功能的业务基类,其中 T 代表变量模型。 /// 抽象类 <see cref="BusinessBaseWithCacheIntervalVariableModel{VarModel}"/>,表示具有缓存间隔功能的业务基类,其中 T 代表变量模型。
/// </summary> /// </summary>
/// <typeparam name="T">变量模型类型</typeparam> /// <typeparam name="VarModel">变量模型类型</typeparam>
public abstract class BusinessBaseWithCacheIntervalVariableModel<T> : BusinessBaseWithCacheVariableModel<T> public abstract class BusinessBaseWithCacheIntervalVariableModel<VarModel> : BusinessBaseWithCacheVariableModel<VarModel>
{ {
/// <summary> /// <summary>
/// 用于定时触发的时间间隔。 /// 用于定时触发的时间间隔。
@@ -110,6 +110,8 @@ public abstract class BusinessBaseWithCacheIntervalVariableModel<T> : BusinessBa
{ {
if (_exTTimerTick.IsTickHappen()) if (_exTTimerTick.IsTickHappen())
{ {
if (LogMessage.LogLevel <= LogLevel.Debug)
LogMessage?.LogDebug($"Interval {typeof(VarModel).Name} data, count {IdVariableRuntimes.Count}");
//间隔推送全部变量 //间隔推送全部变量
var variableRuntimes = IdVariableRuntimes.Select(a => a.Value); var variableRuntimes = IdVariableRuntimes.Select(a => a.Value);
VariableTimeInterval(variableRuntimes, variableRuntimes.Adapt<List<VariableBasicData>>()); VariableTimeInterval(variableRuntimes, variableRuntimes.Adapt<List<VariableBasicData>>());

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

@@ -12,11 +12,12 @@ namespace ThingsGateway.Gateway.Application;
public struct TopicArray public struct TopicArray
{ {
public TopicArray(string topic, byte[] json) public TopicArray(string topic, byte[] json, int count)
{ {
Topic = topic; Json = json; Topic = topic; Json = json; Count = count;
} }
public int Count { get; set; } = 1;
public byte[] Json { get; set; } public byte[] Json { get; set; }
public string Topic { get; set; } public string Topic { get; set; }

View File

@@ -12,10 +12,11 @@ namespace ThingsGateway.Gateway.Application;
public struct TopicJson public struct TopicJson
{ {
public TopicJson(string topic, string json) public TopicJson(string topic, string json, int count)
{ {
Topic = topic; Json = json; Topic = topic; Json = json; Count = count;
} }
public int Count { get; set; } = 1;
public string Json { get; set; } public string Json { get; set; }
public string Topic { get; set; } public string Topic { get; set; }

View File

@@ -51,6 +51,13 @@ public class Variable : BaseDataEntity, IValidatableObject
[Required] [Required]
public virtual string Name { get; set; } public virtual string Name { get; set; }
/// <summary>
/// 采集组
/// </summary>
[SugarColumn(ColumnDescription = "采集组", IsNullable = true)]
[AutoGenerateColumn(Visible = true, Filterable = true, Sortable = true, Order = 1)]
public virtual string CollectGroup { get; set; } = string.Empty;
/// <summary> /// <summary>
/// 分组名称 /// 分组名称
/// </summary> /// </summary>

View File

@@ -97,6 +97,7 @@
"Name": "Name", "Name": "Name",
"Description": "Description", "Description": "Description",
"Group": "Group", "Group": "Group",
"CollectGroup": "CollectGroup",
"DeviceId": "CollectionDevice", "DeviceId": "CollectionDevice",
"DeviceId.MinValue": "{0} cannot be empty", "DeviceId.MinValue": "{0} cannot be empty",
"DeviceId.Required": "{0} cannot be empty", "DeviceId.Required": "{0} cannot be empty",
@@ -452,6 +453,7 @@
"Name.Required": "{0} cannot be empty", "Name.Required": "{0} cannot be empty",
"Description": "Description", "Description": "Description",
"Group": "Group", "Group": "Group",
"CollectGroup": "CollectGroup",
"DeviceId": "CollectionDevice", "DeviceId": "CollectionDevice",
"DeviceId.MinValue": "{0} cannot be empty", "DeviceId.MinValue": "{0} cannot be empty",
"DeviceId.Required": "{0} cannot be empty", "DeviceId.Required": "{0} cannot be empty",

View File

@@ -89,7 +89,8 @@
"Name": "名称", "Name": "名称",
"Name.Required": " {0} 不可为空", "Name.Required": " {0} 不可为空",
"Description": "描述", "Description": "描述",
"Group": "组", "Group": "业务组",
"CollectGroup": "采集组",
"DeviceId": "采集设备", "DeviceId": "采集设备",
"DeviceId.MinValue": " {0} 不可为空", "DeviceId.MinValue": " {0} 不可为空",
"DeviceId.Required": " {0} 不可为空", "DeviceId.Required": " {0} 不可为空",
@@ -486,7 +487,8 @@
"Name": "名称", "Name": "名称",
"Name.Required": " {0} 不可为空", "Name.Required": " {0} 不可为空",
"Description": "描述", "Description": "描述",
"Group": "组", "Group": "业务组",
"CollectGroup": "采集组",
"DeviceId": "采集设备", "DeviceId": "采集设备",
"DeviceId.MinValue": " {0} 不可为空", "DeviceId.MinValue": " {0} 不可为空",
"DeviceId.Required": " {0} 不可为空", "DeviceId.Required": " {0} 不可为空",

View File

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

View File

@@ -8,8 +8,8 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Portable.BouncyCastle" Version="1.9.0" /> <PackageReference Include="Portable.BouncyCastle" Version="1.9.0" />
<PackageReference Include="Rougamo.Fody" Version="5.0.0" /> <PackageReference Include="Rougamo.Fody" Version="5.0.0" />
<PackageReference Include="TouchSocket.Dmtp" Version="3.1.0" /> <PackageReference Include="TouchSocket.Dmtp" Version="3.1.2" />
<PackageReference Include="TouchSocket.WebApi.Swagger" Version="3.1.0" /> <PackageReference Include="TouchSocket.WebApi.Swagger" Version="3.1.2" />
<PackageReference Include="ThingsGateway.Authentication" Version="$(AuthenticationVersion)" /> <PackageReference Include="ThingsGateway.Authentication" Version="$(AuthenticationVersion)" />
</ItemGroup> </ItemGroup>

View File

@@ -129,7 +129,6 @@ public partial class PropertyComponent : IPropertyUIBase
return; return;
} }
var op = new DialogOption() var op = new DialogOption()
{ {
IsScrolling = true, IsScrolling = true,
@@ -144,6 +143,147 @@ public partial class PropertyComponent : IPropertyUIBase
{ {
{nameof(ScriptCheck.Data),data }, {nameof(ScriptCheck.Data),data },
{nameof(ScriptCheck.Script),script }, {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 => {nameof(ScriptCheck.ScriptChanged),EventCallback.Factory.Create<string>(this, v =>
{ {
if (pname == nameof(BusinessPropertyWithCacheIntervalScript.BigTextScriptAlarmModel)) if (pname == nameof(BusinessPropertyWithCacheIntervalScript.BigTextScriptAlarmModel))
@@ -171,3 +311,7 @@ public partial class PropertyComponent : IPropertyUIBase
[Inject] [Inject]
private DialogService DialogService { get; set; } 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("获取变量类实体,可用方法 <code>GlobalData.GetVariable(\"设备名称1\",\"变量名称1\")</code> "))</Alert>
<Alert Icon="fa-solid fa-circle-check" Color="Color.Success">@(new MarkupString("详细说明查看文档对应内容页面"))</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>
<div class="col-6 col-md-6"> <div class="col-6 col-md-6">
<BootstrapLabel Value=@Localizer["Input"] ShowLabelTooltip="true" /> <BootstrapLabel Value=@Localizer["Input"] ShowLabelTooltip="true" />

View File

@@ -56,4 +56,13 @@ public partial class ScriptCheck
} }
[Inject] [Inject]
private IStringLocalizer<DeviceEditComponent> Localizer { get; set; } 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

@@ -44,6 +44,7 @@
<EditorItem @bind-Field="@context.Name" Readonly=BatchEditEnable /> <EditorItem @bind-Field="@context.Name" Readonly=BatchEditEnable />
<EditorItem @bind-Field="@context.Description" /> <EditorItem @bind-Field="@context.Description" />
<EditorItem @bind-Field="@context.CollectGroup" />
<EditorItem @bind-Field="@context.Group" /> <EditorItem @bind-Field="@context.Group" />
<EditorItem @bind-Field="@context.Unit" /> <EditorItem @bind-Field="@context.Unit" />

View File

@@ -7,7 +7,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\ThingsGateway.Gateway.Application\ThingsGateway.Gateway.Application.csproj" /> <ProjectReference Include="..\ThingsGateway.Gateway.Application\ThingsGateway.Gateway.Application.csproj" />
<PackageReference Include="BootstrapBlazor.UniverSheet" Version="9.0.3" /> <PackageReference Include="BootstrapBlazor.UniverSheet" Version="9.0.4" />
<PackageReference Include="BootstrapBlazor.WinBox" Version="9.0.7" /> <PackageReference Include="BootstrapBlazor.WinBox" Version="9.0.7" />
<PackageReference Include="BootstrapBlazor.CodeEditor" Version="9.0.1" /> <PackageReference Include="BootstrapBlazor.CodeEditor" Version="9.0.1" />
<ProjectReference Include="..\..\Admin\ThingsGateway.Admin.Razor\ThingsGateway.Admin.Razor.csproj" /> <ProjectReference Include="..\..\Admin\ThingsGateway.Admin.Razor\ThingsGateway.Admin.Razor.csproj" />

View File

@@ -19,11 +19,12 @@ namespace ThingsGateway.Management;
[Route("openApi/autoUpdate")] [Route("openApi/autoUpdate")]
[RolePermission] [RolePermission]
[LoggingMonitor] [LoggingMonitor]
[ApiController]
[Authorize(AuthenticationSchemes = "Bearer")] [Authorize(AuthenticationSchemes = "Bearer")]
public class AutoUpdateControler : ControllerBase public class AutoUpdateController : ControllerBase
{ {
private IUpdateZipFileHostedService _updateZipFileService; private IUpdateZipFileHostedService _updateZipFileService;
public AutoUpdateControler(IUpdateZipFileHostedService updateZipFileService) public AutoUpdateController(IUpdateZipFileHostedService updateZipFileService)
{ {
_updateZipFileService = updateZipFileService; _updateZipFileService = updateZipFileService;
} }

View File

@@ -14,8 +14,8 @@
"Password": "Password" "Password": "Password"
}, },
"ThingsGateway.Management.AutoUpdateControler": { "ThingsGateway.Management.AutoUpdateController": {
"AutoUpdateControler": "AutoUpdate", "AutoUpdateController": "AutoUpdate",
"Update": "Update" "Update": "Update"
}, },

View File

@@ -13,8 +13,8 @@
"Unregister": "取消注册", "Unregister": "取消注册",
"Password": "注册码" "Password": "注册码"
}, },
"ThingsGateway.Management.AutoUpdateControler": { "ThingsGateway.Management.AutoUpdateController": {
"AutoUpdateControler": "程序更新", "AutoUpdateController": "程序更新",
"Update": "更新" "Update": "更新"
}, },
"ThingsGateway.Upgrade.UpdateZipFile": { "ThingsGateway.Upgrade.UpdateZipFile": {

View File

@@ -55,7 +55,7 @@ internal sealed class RedundancyHostedService : BackgroundService, IRedundancyHo
public string LogPath { get; } public string LogPath { get; }
private TcpDmtpClient TcpDmtpClient; private TcpDmtpClient TcpDmtpClient;
private TcpDmtpService TcpDmtpService; private TcpDmtpService TcpDmtpService;
private TcpDmtpClient GetTcpDmtpClient(RedundancyOptions redundancy) private async Task<TcpDmtpClient> GetTcpDmtpClient(RedundancyOptions redundancy)
{ {
_log = new LoggerGroup() { LogLevel = TouchSocket.Core.LogLevel.Trace }; _log = new LoggerGroup() { LogLevel = TouchSocket.Core.LogLevel.Trace };
_log?.AddLogger(new EasyLogger(Log_Out) { LogLevel = TouchSocket.Core.LogLevel.Trace }); _log?.AddLogger(new EasyLogger(Log_Out) { LogLevel = TouchSocket.Core.LogLevel.Trace });
@@ -81,11 +81,11 @@ internal sealed class RedundancyHostedService : BackgroundService, IRedundancyHo
.SetMaxFailCount(redundancy.MaxErrorCount); .SetMaxFailCount(redundancy.MaxErrorCount);
}); });
tcpDmtpClient.Setup(config); await tcpDmtpClient.SetupAsync(config).ConfigureAwait(false);
return tcpDmtpClient; return tcpDmtpClient;
} }
private TcpDmtpService GetTcpDmtpService(RedundancyOptions redundancy) private async Task<TcpDmtpService> GetTcpDmtpService(RedundancyOptions redundancy)
{ {
_log = new LoggerGroup() { LogLevel = TouchSocket.Core.LogLevel.Trace }; _log = new LoggerGroup() { LogLevel = TouchSocket.Core.LogLevel.Trace };
_log?.AddLogger(new EasyLogger(Log_Out) { LogLevel = TouchSocket.Core.LogLevel.Trace }); _log?.AddLogger(new EasyLogger(Log_Out) { LogLevel = TouchSocket.Core.LogLevel.Trace });
@@ -111,7 +111,7 @@ internal sealed class RedundancyHostedService : BackgroundService, IRedundancyHo
.SetMaxFailCount(redundancy.MaxErrorCount); .SetMaxFailCount(redundancy.MaxErrorCount);
}); });
tcpDmtpService.Setup(config); await tcpDmtpService.SetupAsync(config).ConfigureAwait(false);
return tcpDmtpService; return tcpDmtpService;
} }
@@ -325,13 +325,13 @@ internal sealed class RedundancyHostedService : BackgroundService, IRedundancyHo
{ {
if (RedundancyOptions.IsMaster) if (RedundancyOptions.IsMaster)
{ {
TcpDmtpService = GetTcpDmtpService(RedundancyOptions); TcpDmtpService = await GetTcpDmtpService(RedundancyOptions).ConfigureAwait(false);
await TcpDmtpService.StartAsync().ConfigureAwait(false);//启动 await TcpDmtpService.StartAsync().ConfigureAwait(false);//启动
await ActiveAsync().ConfigureAwait(false); await ActiveAsync().ConfigureAwait(false);
} }
else else
{ {
TcpDmtpClient = GetTcpDmtpClient(RedundancyOptions); TcpDmtpClient = await GetTcpDmtpClient(RedundancyOptions).ConfigureAwait(false);
await StandbyAsync().ConfigureAwait(false); await StandbyAsync().ConfigureAwait(false);
} }
} }

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))] [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 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; 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))] [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 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) 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))] [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 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) Task<NodeOutput> IExpressionNode.ExecuteAsync(NodeInput input, CancellationToken cancellationToken)
{ {

View File

@@ -160,9 +160,19 @@ public class OpcDaMaster : IDisposable
/// <returns></returns> /// <returns></returns>
public Dictionary<string, List<OpcItem>> AddItemsWithSave(List<string> items) public Dictionary<string, List<OpcItem>> AddItemsWithSave(List<string> items)
{ {
int i = 0; lock (this)
ItemDicts = items.ConvertAll(o => new OpcItem(o)).ChunkTrivialBetter(OpcDaProperty.GroupSize).ToDictionary(a => "default" + (i++)); {
return ItemDicts;
int i = ItemDicts.Count;
var addItems = items.ConvertAll(o => new OpcItem(o)).ChunkTrivialBetter(OpcDaProperty.GroupSize).ToDictionary(a => "default" + (i++));
foreach (var item in addItems)
{
ItemDicts.TryAdd(item.Key, item.Value);
}
return addItems;
}
} }
/// <summary> /// <summary>

View File

@@ -398,10 +398,10 @@ public partial class SiemensS7Master : DeviceBase
try 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) 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); await channel.CloseAsync().ConfigureAwait(false);
return true; return true;
} }
@@ -409,16 +409,21 @@ public partial class SiemensS7Master : DeviceBase
catch (OperationCanceledException) { } catch (OperationCanceledException) { }
catch (Exception ex) 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); await channel.CloseAsync().ConfigureAwait(false);
return true; return true;
} }
try 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) 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); await channel.CloseAsync().ConfigureAwait(false);
return true; return true;
} }
@@ -429,7 +434,7 @@ public partial class SiemensS7Master : DeviceBase
catch (OperationCanceledException) { } catch (OperationCanceledException) { }
catch (Exception ex) 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); await channel.CloseAsync().ConfigureAwait(false);
return true; return true;
} }

View File

@@ -12,7 +12,7 @@
</PackageReference> </PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.13.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.13.0" />
<PackageReference Include="xunit" Version="2.9.3" /> <PackageReference Include="xunit" Version="2.9.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.0.2"> <PackageReference Include="xunit.runner.visualstudio" Version="3.1.0">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>

View File

@@ -12,8 +12,6 @@ using BootstrapBlazor.Components;
using Mapster; using Mapster;
using Newtonsoft.Json.Linq;
using SqlSugar; using SqlSugar;
using ThingsGateway.Admin.Application; using ThingsGateway.Admin.Application;
@@ -68,7 +66,7 @@ public partial class QuestDBProducer : BusinessBaseWithCacheIntervalVariableMode
_config.ForType<VariableRuntime, QuestDBHistoryValue>() _config.ForType<VariableRuntime, QuestDBHistoryValue>()
//.Map(dest => dest.Id, src => CommonUtils.GetSingleId()) //.Map(dest => dest.Id, src => CommonUtils.GetSingleId())
.Map(dest => dest.Id, src => src.Id)//Id更改为变量Id .Map(dest => dest.Id, src => src.Id)//Id更改为变量Id
.Map(dest => dest.Value, src => src.Value != null ? src.Value.GetType() == typeof(string) ? src.Value.ToString() : JToken.FromObject(src.Value).ToString() : string.Empty) .Map(dest => dest.Value, src => src.Value == null ? string.Empty : src.Value.ToString() ?? string.Empty)
.Map(dest => dest.CollectTime, (src) => src.CollectTime < DateTime.MinValue ? utcTime : src.CollectTime!.Value.ToUniversalTime())//注意sqlsugar插入时无时区直接utc时间 .Map(dest => dest.CollectTime, (src) => src.CollectTime < DateTime.MinValue ? utcTime : src.CollectTime!.Value.ToUniversalTime())//注意sqlsugar插入时无时区直接utc时间
.Map(dest => dest.CreateTime, (src) => DateTime.UtcNow) .Map(dest => dest.CreateTime, (src) => DateTime.UtcNow)
;//注意sqlsugar插入时无时区直接utc时间 ;//注意sqlsugar插入时无时区直接utc时间

View File

@@ -25,11 +25,20 @@
<div class="col-12 col-md-12"> <div class="col-12 col-md-12">
<BootstrapLabel Value=@SqlDBProducerPropertyLocalizer["BigTextScriptHistoryTable"] ShowLabelTooltip="true" /> <BootstrapLabel Value=@SqlDBProducerPropertyLocalizer["BigTextScriptHistoryTable"] ShowLabelTooltip="true" />
<CodeEditor @bind-Value=@businessProperty.BigTextScriptHistoryTable Language="csharp" Theme="vs-dark" /> <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>
<div class="col-12 col-md-12"> <div class="col-12 col-md-12">
<BootstrapLabel Value=@SqlDBProducerPropertyLocalizer["BigTextScriptRealTable"] ShowLabelTooltip="true" /> <BootstrapLabel Value=@SqlDBProducerPropertyLocalizer["BigTextScriptRealTable"] ShowLabelTooltip="true" />
<CodeEditor @bind-Value=@businessProperty.BigTextScriptRealTable Language="csharp" Theme="vs-dark" /> <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> </div>
</EditTemplate> </EditTemplate>
</EditorItem> </EditorItem>

View File

@@ -8,17 +8,22 @@
// QQ群605534569 // QQ群605534569
// ------------------------------------------------------------------------------ // ------------------------------------------------------------------------------
#pragma warning disable CA2007 // 考虑对等待的任务调用 ConfigureAwait
using BootstrapBlazor.Components; using BootstrapBlazor.Components;
using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.Localization; using Microsoft.Extensions.Localization;
using ThingsGateway.Gateway.Razor;
using ThingsGateway.Plugin.SqlDB;
using ThingsGateway.Razor; using ThingsGateway.Razor;
namespace ThingsGateway.Debug namespace ThingsGateway.Debug
{ {
public partial class SqlDBProducerPropertyRazor : IPropertyUIBase public partial class SqlDBProducerPropertyRazor : IPropertyUIBase
{ {
[Inject]
IStringLocalizer<ThingsGateway.Razor._Imports> RazorLocalizer { get; set; }
[Parameter, EditorRequired] [Parameter, EditorRequired]
@@ -39,6 +44,144 @@ namespace ThingsGateway.Debug
return base.OnParametersSetAsync(); 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

@@ -12,8 +12,6 @@ using BootstrapBlazor.Components;
using Mapster; using Mapster;
using Newtonsoft.Json.Linq;
using SqlSugar; using SqlSugar;
using ThingsGateway.Admin.Application; using ThingsGateway.Admin.Application;
@@ -156,17 +154,11 @@ public partial class SqlDBProducer : BusinessBaseWithCacheIntervalVariableModel<
{ {
_config = new TypeAdapterConfig(); _config = new TypeAdapterConfig();
_config.ForType<VariableRuntime, SQLHistoryValue>() _config.ForType<VariableRuntime, SQLHistoryValue>()
.Map(dest => dest.Id, (src) => CommonUtils.GetSingleId()) //.Map(dest => dest.Id, (src) =>CommonUtils.GetSingleId())
//.Map(dest => dest.Id, src => src.Id)//Id更改为变量Id .Map(dest => dest.Id, src => src.Id)//Id更改为变量Id
.Map(dest => dest.Value, src => src.Value != null ? src.Value.GetType() == typeof(string) ? src.Value.ToString() : JToken.FromObject(src.Value).ToString() : string.Empty) .Map(dest => dest.Value, src => src.Value == null ? string.Empty : src.Value.ToString() ?? string.Empty)
.Map(dest => dest.CreateTime, (src) => DateTime.Now); .Map(dest => dest.CreateTime, (src) => DateTime.Now);
_config.ForType<VariableRuntime, SQLRealValue>()
//.Map(dest => dest.Id, (src) =>CommonUtils.GetSingleId())
.Map(dest => dest.Id, src => src.Id)//Id更改为变量Id
.Map(dest => dest.Value, src => src.Value != null ? src.Value.GetType() == typeof(string) ? src.Value.ToString() : JToken.FromObject(src.Value).ToString() : string.Empty);
_exRealTimerTick = new(_driverPropertys.RealTableBusinessInterval); _exRealTimerTick = new(_driverPropertys.RealTableBusinessInterval);
await base.InitChannelAsync(channel, cancellationToken).ConfigureAwait(false); await base.InitChannelAsync(channel, cancellationToken).ConfigureAwait(false);
@@ -228,7 +220,7 @@ public partial class SqlDBProducer : BusinessBaseWithCacheIntervalVariableModel<
var groups = varList.GroupBy(a => a.Group); var groups = varList.GroupBy(a => a.Group);
foreach (var item in groups) foreach (var item in groups)
{ {
var result = await UpdateAsync(item.Adapt<List<SQLRealValue>>(_config), cancellationToken).ConfigureAwait(false); var result = await UpdateAsync(item.Adapt<List<SQLRealValue>>(), cancellationToken).ConfigureAwait(false);
if (success != result.IsSuccess) if (success != result.IsSuccess)
{ {
if (!result.IsSuccess) if (!result.IsSuccess)
@@ -239,7 +231,7 @@ public partial class SqlDBProducer : BusinessBaseWithCacheIntervalVariableModel<
} }
else else
{ {
var result = await UpdateAsync(varList.Adapt<List<SQLRealValue>>(_config), cancellationToken).ConfigureAwait(false); var result = await UpdateAsync(varList.Adapt<List<SQLRealValue>>(), cancellationToken).ConfigureAwait(false);
if (success != result.IsSuccess) if (success != result.IsSuccess)
{ {
if (!result.IsSuccess) if (!result.IsSuccess)

View File

@@ -19,7 +19,7 @@
<PackageReference Include="SqlSugar.TDengineCore" Version="4.18.8" GeneratePathProperty="true"> <PackageReference Include="SqlSugar.TDengineCore" Version="4.18.31" GeneratePathProperty="true">
<PrivateAssets>contentFiles;compile;build;buildMultitargeting;buildTransitive;analyzers;</PrivateAssets> <PrivateAssets>contentFiles;compile;build;buildMultitargeting;buildTransitive;analyzers;</PrivateAssets>
</PackageReference> </PackageReference>

View File

@@ -13,7 +13,8 @@ using BootstrapBlazor.Components;
using Mapster; using Mapster;
using ThingsGateway.Foundation; using ThingsGateway.Foundation;
using ThingsGateway.NewLife.Extension;
using TouchSocket.Core;
namespace ThingsGateway.Plugin.Webhook; namespace ThingsGateway.Plugin.Webhook;
@@ -133,18 +134,18 @@ public partial class Webhook : BusinessBaseWithCacheIntervalScript<VariableBasic
private readonly HttpClient client = new HttpClient(); private readonly HttpClient client = new HttpClient();
private async Task<OperResult> WebhookUpAsync(string topic, byte[] payLoad, int count, CancellationToken cancellationToken) private async Task<OperResult> WebhookUpAsync(TopicArray topicArray, CancellationToken cancellationToken)
{ {
// 设置请求内容 // 设置请求内容
//var content = new StringContent(json, Encoding.UTF8, "application/json"); //var content = new StringContent(json, Encoding.UTF8, "application/json");
using var content = new ByteArrayContent(payLoad); using var content = new ByteArrayContent(topicArray.Json);
content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json"); content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");
try try
{ {
// 发送POST请求 // 发送POST请求
HttpResponseMessage response = await client.PostAsync(topic, content, cancellationToken).ConfigureAwait(false); HttpResponseMessage response = await client.PostAsync(topicArray.Topic, content, cancellationToken).ConfigureAwait(false);
// 检查响应状态 // 检查响应状态
if (response.IsSuccessStatusCode) if (response.IsSuccessStatusCode)
@@ -152,12 +153,14 @@ public partial class Webhook : BusinessBaseWithCacheIntervalScript<VariableBasic
if (_driverPropertys.DetailLog) if (_driverPropertys.DetailLog)
{ {
if (LogMessage.LogLevel <= TouchSocket.Core.LogLevel.Trace) if (LogMessage.LogLevel <= TouchSocket.Core.LogLevel.Trace)
LogMessage.LogTrace(GetString(topic, payLoad, _memoryVarModelQueue.Count)); LogMessage.LogTrace(GetDetailLogString(topicArray, _memoryVarModelQueue.Count));
else if (LogMessage.LogLevel <= TouchSocket.Core.LogLevel.Debug)
LogMessage.LogDebug(GetCountLogString(topicArray, _memoryVarModelQueue.Count));
} }
else else
{ {
LogMessage.LogTrace($"Topic{topic}{Environment.NewLine}Count{count} {Environment.NewLine} VarModelQueue:{_memoryVarModelQueue.Count}"); if (LogMessage.LogLevel <= TouchSocket.Core.LogLevel.Debug)
LogMessage.LogDebug(GetCountLogString(topicArray, _memoryVarModelQueue.Count));
} }
return new(); return new();
} }
@@ -175,11 +178,11 @@ public partial class Webhook : BusinessBaseWithCacheIntervalScript<VariableBasic
#region private #region private
private async ValueTask<OperResult> Update(List<TopicArray> topicJsonList, int count, CancellationToken cancellationToken) private async ValueTask<OperResult> Update(List<TopicArray> topicArrayList, CancellationToken cancellationToken)
{ {
foreach (var topicJson in topicJsonList) foreach (var topicArray in topicArrayList)
{ {
var result = await WebhookUpAsync(topicJson.Topic, topicJson.Json, count, cancellationToken).ConfigureAwait(false); var result = await WebhookUpAsync(topicArray, cancellationToken).ConfigureAwait(false);
if (cancellationToken.IsCancellationRequested) if (cancellationToken.IsCancellationRequested)
return result; return result;
@@ -203,21 +206,21 @@ public partial class Webhook : BusinessBaseWithCacheIntervalScript<VariableBasic
private ValueTask<OperResult> UpdateAlarmModel(IEnumerable<AlarmVariable> item, CancellationToken cancellationToken) private ValueTask<OperResult> UpdateAlarmModel(IEnumerable<AlarmVariable> item, CancellationToken cancellationToken)
{ {
var topicJsonList = GetAlarmTopicArrays(item); var topicArrayList = GetAlarmTopicArrays(item);
return Update(topicJsonList, item.Count(), cancellationToken); return Update(topicArrayList, cancellationToken);
} }
private ValueTask<OperResult> UpdateDevModel(IEnumerable<DeviceBasicData> item, CancellationToken cancellationToken) private ValueTask<OperResult> UpdateDevModel(IEnumerable<DeviceBasicData> item, CancellationToken cancellationToken)
{ {
var topicJsonList = GetDeviceTopicArray(item); var topicArrayList = GetDeviceTopicArray(item);
return Update(topicJsonList, item.Count(), cancellationToken); return Update(topicArrayList, cancellationToken);
} }
private ValueTask<OperResult> UpdateVarModel(IEnumerable<VariableBasicData> item, CancellationToken cancellationToken) private ValueTask<OperResult> UpdateVarModel(IEnumerable<VariableBasicData> item, CancellationToken cancellationToken)
{ {
var topicJsonList = GetVariableBasicDataTopicArray(item); var topicArrayList = GetVariableBasicDataTopicArray(item);
return Update(topicJsonList, item.Count(), cancellationToken); return Update(topicArrayList, cancellationToken);
} }

View File

@@ -127,11 +127,11 @@ public partial class KafkaProducer : BusinessBaseWithCacheIntervalScript<Variabl
#region private #region private
private async ValueTask<OperResult> Update(List<TopicArray> topicJsonList, int count, CancellationToken cancellationToken) private async ValueTask<OperResult> Update(List<TopicArray> topicArrayList, CancellationToken cancellationToken)
{ {
foreach (var topicJson in topicJsonList) foreach (var topicArray in topicArrayList)
{ {
var result = await KafKaUpAsync(topicJson.Topic, topicJson.Json, count, cancellationToken).ConfigureAwait(false); var result = await KafKaUpAsync(topicArray, cancellationToken).ConfigureAwait(false);
if (success != result.IsSuccess) if (success != result.IsSuccess)
{ {
if (!result.IsSuccess) if (!result.IsSuccess)
@@ -150,20 +150,20 @@ public partial class KafkaProducer : BusinessBaseWithCacheIntervalScript<Variabl
private async ValueTask<OperResult> UpdateAlarmModel(IEnumerable<AlarmVariable> item, CancellationToken cancellationToken) private async ValueTask<OperResult> UpdateAlarmModel(IEnumerable<AlarmVariable> item, CancellationToken cancellationToken)
{ {
var topicJsonList = GetAlarmTopicArrays(item); var topicArrayList = GetAlarmTopicArrays(item);
return await Update(topicJsonList, item.Count(), cancellationToken).ConfigureAwait(false); return await Update(topicArrayList, cancellationToken).ConfigureAwait(false);
} }
private async ValueTask<OperResult> UpdateDevModel(IEnumerable<DeviceBasicData> item, CancellationToken cancellationToken) private async ValueTask<OperResult> UpdateDevModel(IEnumerable<DeviceBasicData> item, CancellationToken cancellationToken)
{ {
var topicJsonList = GetDeviceTopicArray(item); var topicArrayList = GetDeviceTopicArray(item);
return await Update(topicJsonList, item.Count(), cancellationToken).ConfigureAwait(false); return await Update(topicArrayList, cancellationToken).ConfigureAwait(false);
} }
private async ValueTask<OperResult> UpdateVarModel(IEnumerable<VariableBasicData> item, CancellationToken cancellationToken) private async ValueTask<OperResult> UpdateVarModel(IEnumerable<VariableBasicData> item, CancellationToken cancellationToken)
{ {
var topicJsonList = GetVariableBasicDataTopicArray(item); var topicArrayList = GetVariableBasicDataTopicArray(item);
return await Update(topicJsonList, item.Count(), cancellationToken).ConfigureAwait(false); return await Update(topicArrayList, cancellationToken).ConfigureAwait(false);
} }
#endregion private #endregion private
@@ -203,13 +203,13 @@ public partial class KafkaProducer : BusinessBaseWithCacheIntervalScript<Variabl
/// <summary> /// <summary>
/// kafka上传返回上传结果 /// kafka上传返回上传结果
/// </summary> /// </summary>
public async ValueTask<OperResult> KafKaUpAsync(string topic, byte[] payLoad, int count, CancellationToken cancellationToken) public async ValueTask<OperResult> KafKaUpAsync(TopicArray topicArray, CancellationToken cancellationToken)
{ {
try try
{ {
using CancellationTokenSource cancellationTokenSource = new(_driverPropertys.Timeout); using CancellationTokenSource cancellationTokenSource = new(_driverPropertys.Timeout);
using CancellationTokenSource stoppingToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationTokenSource.Token, cancellationToken); using CancellationTokenSource stoppingToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationTokenSource.Token, cancellationToken);
var result = await _producer.ProduceAsync(topic, new Message<Null, byte[]> { Value = payLoad }, stoppingToken.Token).ConfigureAwait(false); var result = await _producer.ProduceAsync(topicArray.Topic, new Message<Null, byte[]> { Value = topicArray.Json }, stoppingToken.Token).ConfigureAwait(false);
if (result.Status != PersistenceStatus.Persisted) if (result.Status != PersistenceStatus.Persisted)
{ {
return new OperResult("Upload fail"); return new OperResult("Upload fail");
@@ -219,12 +219,14 @@ public partial class KafkaProducer : BusinessBaseWithCacheIntervalScript<Variabl
if (_driverPropertys.DetailLog) if (_driverPropertys.DetailLog)
{ {
if (LogMessage.LogLevel <= TouchSocket.Core.LogLevel.Trace) if (LogMessage.LogLevel <= TouchSocket.Core.LogLevel.Trace)
LogMessage.LogTrace(GetString(topic, payLoad, _memoryVarModelQueue.Count)); LogMessage.LogTrace(GetDetailLogString(topicArray, _memoryVarModelQueue.Count));
else if (LogMessage.LogLevel <= TouchSocket.Core.LogLevel.Debug)
LogMessage.LogDebug(GetCountLogString(topicArray, _memoryVarModelQueue.Count));
} }
else else
{ {
LogMessage.LogTrace($"Topic{topic}{Environment.NewLine}Count{count} {Environment.NewLine} VarModelQueue:{_memoryVarModelQueue.Count}"); if (LogMessage.LogLevel <= TouchSocket.Core.LogLevel.Debug)
LogMessage.LogDebug(GetCountLogString(topicArray, _memoryVarModelQueue.Count));
} }
return OperResult.Success; return OperResult.Success;
} }

View File

@@ -80,6 +80,11 @@ public class ModbusMaster : CollectFoundationBase
protected override async Task<List<VariableSourceRead>> ProtectedLoadSourceReadAsync(List<VariableRuntime> deviceVariables) protected override async Task<List<VariableSourceRead>> ProtectedLoadSourceReadAsync(List<VariableRuntime> deviceVariables)
{ {
await Task.CompletedTask.ConfigureAwait(false); await Task.CompletedTask.ConfigureAwait(false);
return _plc.LoadSourceRead<VariableSourceRead>(deviceVariables, _driverPropertys.MaxPack, CurrentDevice.IntervalTime); List<VariableSourceRead> variableSourceReads = new();
foreach (var deviceVariable in deviceVariables.GroupBy(a => a.CollectGroup))
{
variableSourceReads.AddRange(_plc.LoadSourceRead<VariableSourceRead>(deviceVariable, _driverPropertys.MaxPack, CurrentDevice.IntervalTime));
}
return variableSourceReads;
} }
} }

View File

@@ -69,13 +69,13 @@ public partial class MqttClient : BusinessBaseWithCacheIntervalScript<VariableBa
{ {
device = deviceData.Name, device = deviceData.Name,
}; };
var topicJson = new TopicArray() var topicArray = new TopicArray()
{ {
Topic = "v1/gateway/connect", Topic = "v1/gateway/connect",
Json = Serialize(json, _driverPropertys.JsonFormattingIndented) Json = Serialize(json, _driverPropertys.JsonFormattingIndented)
}; };
topicJsonTBList.Add(topicJson); topicJsonTBList.Add(topicArray);
} }
else else
{ {
@@ -83,17 +83,17 @@ public partial class MqttClient : BusinessBaseWithCacheIntervalScript<VariableBa
{ {
device = deviceData.Name, device = deviceData.Name,
}; };
var topicJson = new TopicArray() var topicArray = new TopicArray()
{ {
Topic = "v1/gateway/disconnect", Topic = "v1/gateway/disconnect",
Json = Serialize(json, _driverPropertys.JsonFormattingIndented) Json = Serialize(json, _driverPropertys.JsonFormattingIndented)
}; };
topicJsonTBList.Add(topicJson); topicJsonTBList.Add(topicArray);
} }
} }
var result = await Update(topicJsonTBList, 1, default).ConfigureAwait(false); var result = await Update(topicJsonTBList, default).ConfigureAwait(false);
if (success != result.IsSuccess) if (success != result.IsSuccess)
{ {
if (!result.IsSuccess) if (!result.IsSuccess)
@@ -206,11 +206,11 @@ public partial class MqttClient : BusinessBaseWithCacheIntervalScript<VariableBa
#region private #region private
private async ValueTask<OperResult> Update(List<TopicArray> topicJsonList, int count, CancellationToken cancellationToken) private async ValueTask<OperResult> Update(List<TopicArray> topicArrayList, CancellationToken cancellationToken)
{ {
foreach (var topicJson in topicJsonList) foreach (TopicArray topicArray in topicArrayList)
{ {
var result = await MqttUpAsync(topicJson.Topic, topicJson.Json, count, cancellationToken).ConfigureAwait(false); var result = await MqttUpAsync(topicArray, cancellationToken).ConfigureAwait(false);
if (cancellationToken.IsCancellationRequested) if (cancellationToken.IsCancellationRequested)
return result; return result;
if (success != result.IsSuccess) if (success != result.IsSuccess)
@@ -231,21 +231,21 @@ public partial class MqttClient : BusinessBaseWithCacheIntervalScript<VariableBa
private ValueTask<OperResult> UpdateAlarmModel(IEnumerable<AlarmVariable> item, CancellationToken cancellationToken) private ValueTask<OperResult> UpdateAlarmModel(IEnumerable<AlarmVariable> item, CancellationToken cancellationToken)
{ {
var topicJsonList = GetAlarmTopicArrays(item); var topicArrayList = GetAlarmTopicArrays(item);
return Update(topicJsonList, item.Count(), cancellationToken); return Update(topicArrayList, cancellationToken);
} }
private ValueTask<OperResult> UpdateDevModel(IEnumerable<DeviceBasicData> item, CancellationToken cancellationToken) private ValueTask<OperResult> UpdateDevModel(IEnumerable<DeviceBasicData> item, CancellationToken cancellationToken)
{ {
var topicJsonList = GetDeviceTopicArray(item); var topicArrayList = GetDeviceTopicArray(item);
return Update(topicJsonList, item.Count(), cancellationToken); return Update(topicArrayList, cancellationToken);
} }
private ValueTask<OperResult> UpdateVarModel(IEnumerable<VariableBasicData> item, CancellationToken cancellationToken) private ValueTask<OperResult> UpdateVarModel(IEnumerable<VariableBasicData> item, CancellationToken cancellationToken)
{ {
var topicJsonList = GetVariableBasicDataTopicArray(item); var topicArrayList = GetVariableBasicDataTopicArray(item);
return Update(topicJsonList, item.Count(), cancellationToken); return Update(topicArrayList, cancellationToken);
} }
#endregion private #endregion private
@@ -463,7 +463,7 @@ public partial class MqttClient : BusinessBaseWithCacheIntervalScript<VariableBa
/// <summary> /// <summary>
/// 上传mqtt返回上传结果 /// 上传mqtt返回上传结果
/// </summary> /// </summary>
public async ValueTask<OperResult> MqttUpAsync(string topic, byte[] payLoad, int count, CancellationToken cancellationToken = default) public async ValueTask<OperResult> MqttUpAsync(TopicArray topicArray, CancellationToken cancellationToken = default)
{ {
try try
{ {
@@ -471,20 +471,22 @@ public partial class MqttClient : BusinessBaseWithCacheIntervalScript<VariableBa
if (isConnect.IsSuccess) if (isConnect.IsSuccess)
{ {
var variableMessage = new MqttApplicationMessageBuilder() var variableMessage = new MqttApplicationMessageBuilder()
.WithTopic(topic).WithRetainFlag(true) .WithTopic(topicArray.Topic).WithRetainFlag(true)
.WithPayload(payLoad).Build(); .WithPayload(topicArray.Json).Build();
var result = await _mqttClient.PublishAsync(variableMessage, cancellationToken).ConfigureAwait(false); var result = await _mqttClient.PublishAsync(variableMessage, cancellationToken).ConfigureAwait(false);
if (result.IsSuccess) if (result.IsSuccess)
{ {
if (_driverPropertys.DetailLog) if (_driverPropertys.DetailLog)
{ {
if (LogMessage.LogLevel <= TouchSocket.Core.LogLevel.Trace) if (LogMessage.LogLevel <= TouchSocket.Core.LogLevel.Trace)
LogMessage.LogTrace(GetString(topic, payLoad, _memoryVarModelQueue.Count)); LogMessage.LogTrace(GetDetailLogString(topicArray, _memoryVarModelQueue.Count));
else if (LogMessage.LogLevel <= TouchSocket.Core.LogLevel.Debug)
LogMessage.LogDebug(GetCountLogString(topicArray, _memoryVarModelQueue.Count));
} }
else else
{ {
LogMessage.LogTrace($"Topic{topic}{Environment.NewLine}Count{count} {Environment.NewLine} VarModelQueue:{_memoryVarModelQueue.Count}"); if (LogMessage.LogLevel <= TouchSocket.Core.LogLevel.Debug)
LogMessage.LogDebug(GetCountLogString(topicArray, _memoryVarModelQueue.Count));
} }
return OperResult.Success; return OperResult.Success;
} }

View File

@@ -46,7 +46,6 @@ namespace ThingsGateway.Plugin.Mqtt
if (mqttClientProperty.TLS == true) if (mqttClientProperty.TLS == true)
{ {
{ {
var filePath = Path.Combine("PluginFile", Id, nameof(mqttClientProperty.CAFile)); var filePath = Path.Combine("PluginFile", Id, nameof(mqttClientProperty.CAFile));
if (!Directory.Exists(filePath))//如果不存在就创建文件夹 if (!Directory.Exists(filePath))//如果不存在就创建文件夹
Directory.CreateDirectory(filePath); Directory.CreateDirectory(filePath);
@@ -230,7 +229,6 @@ namespace ThingsGateway.Plugin.Mqtt
return; return;
} }
var op = new DialogOption() var op = new DialogOption()
{ {
IsScrolling = true, IsScrolling = true,
@@ -245,6 +243,142 @@ namespace ThingsGateway.Plugin.Mqtt
{ {
{nameof(ScriptCheck.Data),data }, {nameof(ScriptCheck.Data),data },
{nameof(ScriptCheck.Script),script }, {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 => {nameof(ScriptCheck.ScriptChanged),EventCallback.Factory.Create<string>(this, v =>
{ {
if (pname == nameof(BusinessPropertyWithCacheIntervalScript.BigTextScriptAlarmModel)) if (pname == nameof(BusinessPropertyWithCacheIntervalScript.BigTextScriptAlarmModel))
@@ -269,6 +403,7 @@ namespace ThingsGateway.Plugin.Mqtt
} }
[Inject] [Inject]
private DialogService DialogService { get; set; } private DialogService DialogService { get; set; }
} }

View File

@@ -141,11 +141,11 @@ public partial class MqttServer : BusinessBaseWithCacheIntervalScript<VariableBa
} }
#region private #region private
private async ValueTask<OperResult> Update(List<TopicArray> topicJsonList, int count, CancellationToken cancellationToken) private async ValueTask<OperResult> Update(List<TopicArray> topicArrayList, CancellationToken cancellationToken)
{ {
foreach (var topicJson in topicJsonList) foreach (var topicArray in topicArrayList)
{ {
var result = await MqttUpAsync(topicJson.Topic, topicJson.Json, count, cancellationToken).ConfigureAwait(false); var result = await MqttUpAsync(topicArray, cancellationToken).ConfigureAwait(false);
if (success != result.IsSuccess) if (success != result.IsSuccess)
{ {
if (!result.IsSuccess) if (!result.IsSuccess)
@@ -164,21 +164,21 @@ public partial class MqttServer : BusinessBaseWithCacheIntervalScript<VariableBa
private ValueTask<OperResult> UpdateAlarmModel(IEnumerable<AlarmVariable> item, CancellationToken cancellationToken) private ValueTask<OperResult> UpdateAlarmModel(IEnumerable<AlarmVariable> item, CancellationToken cancellationToken)
{ {
var topicJsonList = GetAlarmTopicArrays(item); var topicArrayList = GetAlarmTopicArrays(item);
return Update(topicJsonList, item.Count(), cancellationToken); return Update(topicArrayList, cancellationToken);
} }
private ValueTask<OperResult> UpdateDevModel(IEnumerable<DeviceBasicData> item, CancellationToken cancellationToken) private ValueTask<OperResult> UpdateDevModel(IEnumerable<DeviceBasicData> item, CancellationToken cancellationToken)
{ {
var topicJsonList = GetDeviceTopicArray(item); var topicArrayList = GetDeviceTopicArray(item);
return Update(topicJsonList, item.Count(), cancellationToken); return Update(topicArrayList, cancellationToken);
} }
private ValueTask<OperResult> UpdateVarModel(IEnumerable<VariableBasicData> item, CancellationToken cancellationToken) private ValueTask<OperResult> UpdateVarModel(IEnumerable<VariableBasicData> item, CancellationToken cancellationToken)
{ {
var topicJsonList = GetVariableBasicDataTopicArray(item); var topicArrayList = GetVariableBasicDataTopicArray(item);
return Update(topicJsonList, item.Count(), cancellationToken); return Update(topicArrayList, cancellationToken);
} }
#endregion private #endregion private
@@ -261,12 +261,12 @@ public partial class MqttServer : BusinessBaseWithCacheIntervalScript<VariableBa
{ {
foreach (var item in varData) foreach (var item in varData)
{ {
var topicJsonList = GetVariableBasicData(item); var topicArrayList = GetVariableBasicDataTopicArray(item);
foreach (var topicJson in topicJsonList) foreach (var topicArray in topicArrayList)
{ {
Messages.Add(new MqttApplicationMessageBuilder() Messages.Add(new MqttApplicationMessageBuilder()
.WithTopic(topicJson.Topic) .WithTopic(topicArray.Topic)
.WithPayload(topicJson.Json).Build()); .WithPayload(topicArray.Json).Build());
} }
} }
} }
@@ -276,12 +276,12 @@ public partial class MqttServer : BusinessBaseWithCacheIntervalScript<VariableBa
{ {
foreach (var item in devData) foreach (var item in devData)
{ {
var topicJsonList = GetDeviceData(item); var topicArrayList = GetDeviceTopicArray(item);
foreach (var topicJson in topicJsonList) foreach (var topicArray in topicArrayList)
{ {
Messages.Add(new MqttApplicationMessageBuilder() Messages.Add(new MqttApplicationMessageBuilder()
.WithTopic(topicJson.Topic) .WithTopic(topicArray.Topic)
.WithPayload(topicJson.Json).Build()); .WithPayload(topicArray.Json).Build());
} }
} }
} }
@@ -290,12 +290,12 @@ public partial class MqttServer : BusinessBaseWithCacheIntervalScript<VariableBa
{ {
foreach (var item in alramData) foreach (var item in alramData)
{ {
var topicJsonList = GetAlarms(item); var topicArrayList = GetAlarmTopicArrays(item);
foreach (var topicJson in topicJsonList) foreach (var topicArray in topicArrayList)
{ {
Messages.Add(new MqttApplicationMessageBuilder() Messages.Add(new MqttApplicationMessageBuilder()
.WithTopic(topicJson.Topic) .WithTopic(topicArray.Topic)
.WithPayload(topicJson.Json).Build()); .WithPayload(topicArray.Json).Build());
} }
} }
} }
@@ -394,25 +394,27 @@ public partial class MqttServer : BusinessBaseWithCacheIntervalScript<VariableBa
/// <summary> /// <summary>
/// 上传mqtt返回上传结果 /// 上传mqtt返回上传结果
/// </summary> /// </summary>
public async ValueTask<OperResult> MqttUpAsync(string topic, byte[] payLoad, int count, CancellationToken cancellationToken = default) public async ValueTask<OperResult> MqttUpAsync(TopicArray topicArray, CancellationToken cancellationToken = default)
{ {
try try
{ {
var message = new MqttApplicationMessageBuilder() var message = new MqttApplicationMessageBuilder()
.WithTopic(topic) .WithTopic(topicArray.Topic)
.WithPayload(payLoad).Build(); .WithPayload(topicArray.Json).Build();
await _mqttServer.InjectApplicationMessage( await _mqttServer.InjectApplicationMessage(
new InjectedMqttApplicationMessage(message), cancellationToken).ConfigureAwait(false); new InjectedMqttApplicationMessage(message), cancellationToken).ConfigureAwait(false);
if (_driverPropertys.DetailLog) if (_driverPropertys.DetailLog)
{ {
if (LogMessage.LogLevel <= TouchSocket.Core.LogLevel.Trace) if (LogMessage.LogLevel <= TouchSocket.Core.LogLevel.Trace)
LogMessage.LogTrace(GetString(topic, payLoad, _memoryVarModelQueue.Count)); LogMessage.LogTrace(GetDetailLogString(topicArray, _memoryVarModelQueue.Count));
else if (LogMessage.LogLevel <= TouchSocket.Core.LogLevel.Debug)
LogMessage.LogDebug(GetCountLogString(topicArray, _memoryVarModelQueue.Count));
} }
else else
{ {
LogMessage.LogTrace($"Topic{topic}{Environment.NewLine}Count{count} {Environment.NewLine} VarModelQueue:{_memoryVarModelQueue.Count}"); if (LogMessage.LogLevel <= TouchSocket.Core.LogLevel.Debug)
LogMessage.LogDebug(GetCountLogString(topicArray, _memoryVarModelQueue.Count));
} }
return OperResult.Success; return OperResult.Success;
} }

View File

@@ -122,25 +122,31 @@ public class OpcDaMaster : CollectBase
{ {
if (deviceVariables.Count > 0) if (deviceVariables.Count > 0)
{ {
var result = _plc.AddItemsWithSave(deviceVariables.Where(a => !string.IsNullOrEmpty(a.RegisterAddress)).Select(a => a.RegisterAddress!).ToList()); List<VariableSourceRead> variableSourceReads = new List<VariableSourceRead>();
var sourVars = result?.Select( foreach (var deviceVariableGroups in deviceVariables.GroupBy(a => a.CollectGroup))
it => {
{
var read = new VariableSourceRead()
{
TimeTick = new(_driverProperties.UpdateRate.ToString()),
RegisterAddress = it.Key,
};
HashSet<string> ids = new(it.Value.Select(b => b.ItemID));
var variables = deviceVariables.Where(a => ids.Contains(a.RegisterAddress)); var result = _plc.AddItemsWithSave(deviceVariableGroups.Where(a => !string.IsNullOrEmpty(a.RegisterAddress)).Select(a => a.RegisterAddress!).ToList());
foreach (var v in variables) var sourVars = result?.Select(
it =>
{ {
read.AddVariable(v); var read = new VariableSourceRead()
} {
return read; TimeTick = new(_driverProperties.UpdateRate.ToString()),
}).ToList(); RegisterAddress = it.Key,
return sourVars; };
HashSet<string> ids = new(it.Value.Select(b => b.ItemID));
var variables = deviceVariableGroups.Where(a => ids.Contains(a.RegisterAddress));
foreach (var v in variables)
{
read.AddVariable(v);
}
return read;
}).ToList();
variableSourceReads.AddRange(sourVars);
}
return variableSourceReads;
} }
else else
{ {

View File

@@ -187,24 +187,27 @@ public class OpcUaMaster : CollectBase
await Task.CompletedTask.ConfigureAwait(false); await Task.CompletedTask.ConfigureAwait(false);
if (deviceVariables.Count > 0) if (deviceVariables.Count > 0)
{ {
var dataLists = deviceVariables.ChunkBetter(_driverProperties.GroupSize); List<VariableSourceRead> variableSourceReads = new List<VariableSourceRead>();
foreach (var deviceVariableGroups in deviceVariables.GroupBy(a => a.CollectGroup))
var dataResult = new List<VariableSourceRead>();
foreach (var variable in dataLists)
{ {
var sourVars = new VariableSourceRead() var dataLists = deviceVariableGroups.ChunkBetter(_driverProperties.GroupSize);
{
TimeTick = new(_driverProperties.UpdateRate.ToString()),
RegisterAddress = Guid.NewGuid().ToString(),
};
foreach (var item in variable)
{
sourVars.AddVariable(item);
}
dataResult.Add(sourVars);
}
return dataResult; foreach (var variable in dataLists)
{
var sourVars = new VariableSourceRead()
{
TimeTick = new(_driverProperties.UpdateRate.ToString()),
RegisterAddress = Guid.NewGuid().ToString(),
};
foreach (var item in variable)
{
sourVars.AddVariable(item);
}
variableSourceReads.Add(sourVars);
}
}
return variableSourceReads;
} }
else else
{ {

View File

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

View File

@@ -128,11 +128,11 @@ public partial class RabbitMQProducer : BusinessBaseWithCacheIntervalScript<Vari
#region private #region private
private async ValueTask<OperResult> Update(List<TopicArray> topicJsonList, int count, CancellationToken cancellationToken) private async ValueTask<OperResult> Update(List<TopicArray> topicArrayList, CancellationToken cancellationToken)
{ {
foreach (var topicJson in topicJsonList) foreach (var topicArray in topicArrayList)
{ {
var result = await Publish(topicJson.Topic, topicJson.Json, count, cancellationToken).ConfigureAwait(false); var result = await RabbitMQUpAsync(topicArray, cancellationToken).ConfigureAwait(false);
if (success != result.IsSuccess) if (success != result.IsSuccess)
{ {
if (!result.IsSuccess) if (!result.IsSuccess)
@@ -152,20 +152,20 @@ public partial class RabbitMQProducer : BusinessBaseWithCacheIntervalScript<Vari
private ValueTask<OperResult> UpdateAlarmModel(IEnumerable<AlarmVariable> item, CancellationToken cancellationToken) private ValueTask<OperResult> UpdateAlarmModel(IEnumerable<AlarmVariable> item, CancellationToken cancellationToken)
{ {
var topicJsonList = GetAlarmTopicArrays(item); var topicArrayList = GetAlarmTopicArrays(item);
return Update(topicJsonList, item.Count(), cancellationToken); return Update(topicArrayList, cancellationToken);
} }
private ValueTask<OperResult> UpdateDevModel(IEnumerable<DeviceBasicData> item, CancellationToken cancellationToken) private ValueTask<OperResult> UpdateDevModel(IEnumerable<DeviceBasicData> item, CancellationToken cancellationToken)
{ {
var topicJsonList = GetDeviceTopicArray(item); var topicArrayList = GetDeviceTopicArray(item);
return Update(topicJsonList, item.Count(), cancellationToken); return Update(topicArrayList, cancellationToken);
} }
private ValueTask<OperResult> UpdateVarModel(IEnumerable<VariableBasicData> item, CancellationToken cancellationToken) private ValueTask<OperResult> UpdateVarModel(IEnumerable<VariableBasicData> item, CancellationToken cancellationToken)
{ {
var topicJsonList = GetVariableBasicDataTopicArray(item); var topicArrayList = GetVariableBasicDataTopicArray(item);
return Update(topicJsonList, item.Count(), cancellationToken); return Update(topicArrayList, cancellationToken);
} }
#endregion private #endregion private
@@ -206,23 +206,25 @@ public partial class RabbitMQProducer : BusinessBaseWithCacheIntervalScript<Vari
/// <summary> /// <summary>
/// 上传,返回上传结果 /// 上传,返回上传结果
/// </summary> /// </summary>
public async Task<OperResult> Publish(string topic, byte[] payLoad, int count, CancellationToken cancellationToken) public async Task<OperResult> RabbitMQUpAsync(TopicArray topicArray, CancellationToken cancellationToken)
{ {
try try
{ {
if (_channel != null) if (_channel != null)
{ {
await _channel.BasicPublishAsync(_driverPropertys.ExchangeName, topic, payLoad, cancellationToken).ConfigureAwait(false); await _channel.BasicPublishAsync(_driverPropertys.ExchangeName, topicArray.Topic, topicArray.Json, cancellationToken).ConfigureAwait(false);
if (_driverPropertys.DetailLog) if (_driverPropertys.DetailLog)
{ {
if (LogMessage.LogLevel <= TouchSocket.Core.LogLevel.Trace) if (LogMessage.LogLevel <= TouchSocket.Core.LogLevel.Trace)
LogMessage.LogTrace(GetString(topic, payLoad, _memoryVarModelQueue.Count)); LogMessage.LogTrace(GetDetailLogString(topicArray, _memoryVarModelQueue.Count));
else if (LogMessage.LogLevel <= TouchSocket.Core.LogLevel.Debug)
LogMessage.LogDebug(GetCountLogString(topicArray, _memoryVarModelQueue.Count));
} }
else else
{ {
LogMessage.LogTrace($"Topic{topic}{Environment.NewLine}Count{count} {Environment.NewLine} VarModelQueue:{_memoryVarModelQueue.Count}"); if (LogMessage.LogLevel <= TouchSocket.Core.LogLevel.Debug)
LogMessage.LogDebug(GetCountLogString(topicArray, _memoryVarModelQueue.Count));
} }
return OperResult.Success; return OperResult.Success;
} }

View File

@@ -221,7 +221,12 @@ public class SiemensS7Master : CollectFoundationBase
{ {
} }
return _plc.LoadSourceRead<VariableSourceRead>(deviceVariables, _plc.OnLine ? _plc.PduLength : _driverPropertys.MaxPack, CurrentDevice.IntervalTime); List<VariableSourceRead> variableSourceReads = new();
foreach (var deviceVariable in deviceVariables.GroupBy(a => a.CollectGroup))
{
variableSourceReads.AddRange(_plc.LoadSourceRead<VariableSourceRead>(deviceVariable, _driverPropertys.MaxPack, CurrentDevice.IntervalTime));
}
return variableSourceReads;
} }
finally { } finally { }
} }

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.Authorization;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Components.Authorization; 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.Hosting;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.HttpOverrides; using Microsoft.AspNetCore.HttpOverrides;
@@ -24,6 +27,7 @@ using Microsoft.Extensions.Options;
using Newtonsoft.Json; using Newtonsoft.Json;
using System.Security.Cryptography.X509Certificates;
using System.Text; using System.Text;
using System.Text.Encodings.Web; using System.Text.Encodings.Web;
using System.Text.Unicode; using System.Text.Unicode;
@@ -273,6 +277,21 @@ public class Startup : AppStartup
services.AddSignalR(); services.AddSignalR();
#endregion #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" /> <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.Application\ThingsGateway.Gateway.Application.csproj" />
<ProjectReference Include="..\Gateway\ThingsGateway.Gateway.Razor\ThingsGateway.Gateway.Razor.csproj" /> <ProjectReference Include="..\Gateway\ThingsGateway.Gateway.Razor\ThingsGateway.Gateway.Razor.csproj" />
<ProjectReference Include="..\Gateway\ThingsGateway.Management\ThingsGateway.Management.csproj" /> <ProjectReference Include="..\Gateway\ThingsGateway.Management\ThingsGateway.Management.csproj" />
@@ -19,8 +19,8 @@
<!--nuget包解压复制文件上下文动态加载网关管理和网关冗余--> <!--nuget包解压复制文件上下文动态加载网关管理和网关冗余-->
<Import Project="..\ThingsGateway.Server\targets\GatewayOther.targets" Condition=" '$(SolutionName)' == 'ThingsGatewayRelease' " /> <Import Project="..\ThingsGateway.Server\targets\GatewayOther.targets" Condition=" '$(SolutionName)' == 'ThingsGatewayRelease' " />
<ItemGroup Condition=" '$(SolutionName)' == 'ThingsGatewayRelease' " > <ItemGroup Condition=" '$(SolutionName)' == 'ThingsGatewayRelease' ">
<PackageReference Include="ThingsGateway.Photino.Blazor" Version="$(Version)" /> <PackageReference Include="ThingsGateway.Photino.Blazor" Version="$(Version)" />
</ItemGroup> </ItemGroup>
@@ -29,15 +29,17 @@
<!--直接引用--> <!--直接引用-->
<Import Project="..\ThingsGateway.Server\targets\PluginDebug.targets" Condition=" '$(SolutionName)' != 'ThingsGatewayPro' AND '$(Configuration)' == 'Debug' " /> <Import Project="..\ThingsGateway.Server\targets\PluginDebug.targets" Condition=" '$(SolutionName)' != 'ThingsGatewayPro' AND '$(Configuration)' == 'Debug' " />
<!--直接引用Pro-->
<Import Project="..\ThingsGateway.Server\targets\PluginDebug.targets" Condition=" '$(SolutionName)' == 'ThingsGatewayPro' AND '$(Configuration)' == 'Debug'" />
<Import Project="..\ThingsGateway.Server\targets\PluginContext.targets" Condition=" '$(SolutionName)' == 'ThingsGatewayPro' AND '$(Configuration)' != 'Debug' " />
<!--nuget包解压复制文件插件域隔离动态加载--> <!--nuget包解压复制文件插件域隔离动态加载-->
<!--<Import Project="targets\Plugin.targets" />--> <!--<Import Project="targets\Plugin.targets" />-->
<!--nuget包解压复制文件上下文动态加载Pro插件--> <!--nuget包解压复制文件上下文动态加载Pro插件-->
<Import Project="..\ThingsGateway.Server\targets\Pro2.targets" Condition=" '$(SolutionName)' != 'ThingsGatewayPro' OR '$(Configuration)' != 'Debug'" /> <Import Project="..\ThingsGateway.Server\targets\Pro2.targets" Condition=" '$(SolutionName)' != 'ThingsGatewayPro' OR '$(Configuration)' != 'Debug'" />
<!--直接引用Pro-->
<Import Project="..\ThingsGateway.Server\targets\PluginDebug.targets" Condition=" '$(SolutionName)' == 'ThingsGatewayPro' AND '$(Configuration)' == 'Debug'" />
<Import Project="..\ThingsGateway.Server\targets\PluginContext.targets" Condition=" '$(SolutionName)' == 'ThingsGatewayPro' AND '$(Configuration)' != 'Debug' " />
<Import Project="..\ThingsGateway.Server\targets\ProPluginDebug.targets" Condition=" '$(SolutionName)' == 'ThingsGatewayPro' AND '$(Configuration)' == 'Debug'" /> <Import Project="..\ThingsGateway.Server\targets\ProPluginDebug.targets" Condition=" '$(SolutionName)' == 'ThingsGatewayPro' AND '$(Configuration)' == 'Debug'" />
@@ -87,6 +89,9 @@
<Compile Include="..\ThingsGateway.Server\Program\SingleFilePublish.cs" Link="Program\SingleFilePublish.cs" /> <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" /> <Content Include="..\ThingsGateway.Server\wwwroot\favicon.ico" Link="wwwroot\favicon.ico" />
@@ -119,11 +124,23 @@
</EmbeddedResource> </EmbeddedResource>
</ItemGroup> </ItemGroup>
<ItemGroup>
<Content Remove="launchSettings.json" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<Content Include="favicon.ico"> <Content Include="favicon.ico">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content> </Content>
</ItemGroup> </ItemGroup>
<ItemGroup>
<None Include="Properties\launchSettings.json">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>Never</CopyToPublishDirectory>
</None>
</ItemGroup>
</Project> </Project>

View File

@@ -6,7 +6,7 @@
"Startway": "DOTNET", // 启动方式DOTNET (直接启动) WindowsServicewindows服务 PM2, Systemctl等不需要配置。对应文件夹下的命令文件 "Startway": "DOTNET", // 启动方式DOTNET (直接启动) WindowsServicewindows服务 PM2, Systemctl等不需要配置。对应文件夹下的命令文件
"AppSettings": { "AppSettings": {
"InjectSpecificationDocument": true, // 生产环境是否开启Swagger "InjectSpecificationDocument": true, // 是否开启Swagger
"ExternalAssemblies": [ "Plugins" ], // 插件目录 "ExternalAssemblies": [ "Plugins" ], // 插件目录
// nuget动态加载的程序集 // nuget动态加载的程序集

View File

@@ -6,7 +6,7 @@
"Startway": "", // 启动方式DOTNET (直接启动) WindowsServicewindows服务 PM2, Systemctl等不需要配置。对应文件夹下的命令文件 "Startway": "", // 启动方式DOTNET (直接启动) WindowsServicewindows服务 PM2, Systemctl等不需要配置。对应文件夹下的命令文件
"AppSettings": { "AppSettings": {
"InjectSpecificationDocument": true, // 生产环境是否开启Swagger "InjectSpecificationDocument": false, // 是否开启Swagger
"ExternalAssemblies": [ "Plugins" ], // 插件目录 "ExternalAssemblies": [ "Plugins" ], // 插件目录
// nuget动态加载的程序集 // nuget动态加载的程序集

View File

@@ -10,6 +10,9 @@
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Components.Authorization; using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption;
using Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel;
using Microsoft.AspNetCore.HttpOverrides; using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.AspNetCore.Mvc.Controllers; using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.StaticFiles; using Microsoft.AspNetCore.StaticFiles;
@@ -18,6 +21,7 @@ using Microsoft.Extensions.Options;
using Newtonsoft.Json; using Newtonsoft.Json;
using System.Security.Cryptography.X509Certificates;
using System.Text; using System.Text;
using System.Text.Encodings.Web; using System.Text.Encodings.Web;
using System.Text.Unicode; using System.Text.Unicode;
@@ -291,6 +295,21 @@ public class Startup : AppStartup
services.AddAuthorizationCore(); services.AddAuthorizationCore();
services.AddScoped<IAuthorizationHandler, BlazorServerAuthenticationHandler>(); services.AddScoped<IAuthorizationHandler, BlazorServerAuthenticationHandler>();
services.AddScoped<AuthenticationStateProvider, BlazorServerAuthenticationStateProvider>(); 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"> <Content Include="favicon.ico">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content> </Content>
<None Update="ThingsGateway.pfx">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="WindowsService"> <None Update="WindowsService">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None> </None>

Binary file not shown.

View File

@@ -16,7 +16,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="TouchSocket.Dmtp" Version="3.1.0" /> <PackageReference Include="TouchSocket.Dmtp" Version="3.1.2" />
</ItemGroup> </ItemGroup>

View File

@@ -23,10 +23,10 @@ namespace ThingsGateway.Upgrade;
[RolePermission] [RolePermission]
[LoggingMonitor] [LoggingMonitor]
[Authorize(AuthenticationSchemes = "Bearer")] [Authorize(AuthenticationSchemes = "Bearer")]
public class AutoUpdateControler : ControllerBase public class AutoUpdateController : ControllerBase
{ {
private IUpdateZipFileHostedService _updateZipFileService; private IUpdateZipFileHostedService _updateZipFileService;
public AutoUpdateControler(IUpdateZipFileHostedService updateZipFileService) public AutoUpdateController(IUpdateZipFileHostedService updateZipFileService)
{ {
_updateZipFileService = updateZipFileService; _updateZipFileService = updateZipFileService;
} }

View File

@@ -10,6 +10,9 @@
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Components.Authorization; using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption;
using Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel;
using Microsoft.AspNetCore.HttpOverrides; using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.AspNetCore.Mvc.Controllers; using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.StaticFiles; using Microsoft.AspNetCore.StaticFiles;
@@ -18,6 +21,7 @@ using Microsoft.Extensions.Options;
using Newtonsoft.Json; using Newtonsoft.Json;
using System.Security.Cryptography.X509Certificates;
using System.Text; using System.Text;
using System.Text.Encodings.Web; using System.Text.Encodings.Web;
using System.Text.Unicode; using System.Text.Unicode;
@@ -297,6 +301,21 @@ public class Startup : AppStartup
services.AddAuthorizationCore(); services.AddAuthorizationCore();
services.AddScoped<IAuthorizationHandler, BlazorServerAuthenticationHandler>(); services.AddScoped<IAuthorizationHandler, BlazorServerAuthenticationHandler>();
services.AddScoped<AuthenticationStateProvider, BlazorServerAuthenticationStateProvider>(); 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"> <None Update="pm2-linux.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None> </None>
<None Update="ThingsGateway.pfx">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="WindowsServiceDelete.bat"> <None Update="WindowsServiceDelete.bat">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None> </None>

View File

@@ -1,5 +1,5 @@
cd .. cd ..
sc create ThingsGateway binPath= %~dp0ThingsGateway.AdminServer.exe start= auto sc create ThingsGateway binPath= %~dp0ThingsGateway.UpgradeServer.exe start= auto
sc description ThingsGateway "ThingsGateway" sc description ThingsGateway.UpgradeServer "ThingsGateway.UpgradeServer"
Net Start ThingsGateway Net Start ThingsGateway.UpgradeServer
pause pause

View File

@@ -1,3 +1,3 @@
net stop ThingsGateway net stop ThingsGateway.UpgradeServer
sc delete ThingsGateway sc delete ThingsGateway.UpgradeServer
pause pause

View File

@@ -1,8 +1,7 @@
{ {
"urls": "http://*:5500",
"ConfigurationScanDirectories": [ "Configuration", "" ], // 扫描配置文件json文件夹自动合并该文件夹里面所有json文件 "ConfigurationScanDirectories": [ "Configuration", "" ], // 扫描配置文件json文件夹自动合并该文件夹里面所有json文件
"IgnoreConfigurationFiles": [ "" ], "IgnoreConfigurationFiles": [ "" ],
"ExternalAssemblies": [ "" ] "ExternalAssemblies": [ "" ],
"DetailedErrors": true
} }

View File

@@ -3,6 +3,7 @@
"ConfigurationScanDirectories": [ "Configuration", "" ], // 扫描配置文件json文件夹自动合并该文件夹里面所有json文件 "ConfigurationScanDirectories": [ "Configuration", "" ], // 扫描配置文件json文件夹自动合并该文件夹里面所有json文件
"IgnoreConfigurationFiles": [ "" ], "IgnoreConfigurationFiles": [ "" ],
"ExternalAssemblies": [ "" ] "ExternalAssemblies": [ "" ],
"DetailedErrors": true
} }

View File

@@ -1,22 +0,0 @@
{
"apps": {
"name": "ThingsGateway",
"script": "dotnet",
"exec_mode": "fork",
"error_file": "logs/pm2err.log",
"out_file": "logs/pm2out.log",
"merge_logs": true,
"log_date_format": "YYYY-MM-DD HH:mm:ss",
"min_uptime": "60s",
"max_restarts": 30,
"autorestart": true,
"restart_delay": "60",
"args": [
"ThingsGateway.UpgradeServer.dll",
" --urls=http://*:5000"
],
"env": {
"ASPNETCORE_ENVIRONMENT": "Production"
}
}
}

View File

@@ -0,0 +1,5 @@
{
"configProperties": {
"System.Runtime.EnableWriteXorExecute": false
}
}

View File

@@ -1,6 +1,6 @@
<Project> <Project>
<PropertyGroup> <PropertyGroup>
<Version>10.5.9</Version> <Version>10.5.18</Version>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>