From 556819c90cbaaa6e2804a5b21a66190c29353125 Mon Sep 17 00:00:00 2001
From: "2248356998 qq.com" <2248356998@qq.com>
Date: Tue, 30 Sep 2025 15:25:15 +0800
Subject: [PATCH] 10.11.83
---
.../Entity/VerificatInfo.cs | 2 ++
.../OAuth/AdminOAuthHandler.cs | 4 +--
.../Services/Auth/AuthService.cs | 4 +--
.../Util/AdminResourceUtil.cs | 2 +-
src/Directory.Build.props | 6 ++--
.../Extension/ChannelOptionsExtensions.cs | 18 +++++++++--
.../Device/DeviceBase.cs | 13 +++-----
.../GlobalData/GlobalData.cs | 10 +++++-
.../Services/Device/DeviceService.cs | 2 +-
.../ChannelDeviceTree.razor.cs | 1 -
.../Benchmark/ModbusBenchmark.cs | 4 +--
.../Benchmark/S7Benchmark.cs | 1 -
.../OpcUaMaster/OpcUaMaster.cs | 8 ++++-
.../Utils/CollectionExtension.cs | 32 +++++++++++++++++++
.../OpcDaMaster/OpcDaMaster.cs | 16 ++++++----
.../OpcUaMaster/OpcUaMaster.cs | 14 +++++---
.../Pages/OpcUaMaster.razor.cs | 2 +-
17 files changed, 102 insertions(+), 37 deletions(-)
diff --git a/src/Admin/ThingsGateway.Admin.Application/Entity/VerificatInfo.cs b/src/Admin/ThingsGateway.Admin.Application/Entity/VerificatInfo.cs
index a52e3019b..a13bf9b7f 100644
--- a/src/Admin/ThingsGateway.Admin.Application/Entity/VerificatInfo.cs
+++ b/src/Admin/ThingsGateway.Admin.Application/Entity/VerificatInfo.cs
@@ -45,6 +45,7 @@ public class VerificatInfo : PrimaryIdEntity
/// 登录IP
///
[AutoGenerateColumn(Filterable = true, Sortable = true, Width = 200)]
+ [SugarColumn(IsNullable = true)]
public string LoginIp { get; set; }
///
@@ -78,5 +79,6 @@ public class VerificatInfo : PrimaryIdEntity
/// 登录设备
///
[AutoGenerateColumn(Filterable = true, Sortable = true, Width = 100)]
+ [SugarColumn(IsNullable = true)]
public string Device { get; set; }
}
diff --git a/src/Admin/ThingsGateway.Admin.Application/OAuth/AdminOAuthHandler.cs b/src/Admin/ThingsGateway.Admin.Application/OAuth/AdminOAuthHandler.cs
index 313759033..9960b7a55 100644
--- a/src/Admin/ThingsGateway.Admin.Application/OAuth/AdminOAuthHandler.cs
+++ b/src/Admin/ThingsGateway.Admin.Application/OAuth/AdminOAuthHandler.cs
@@ -145,7 +145,7 @@ public class AdminOAuthHandler(
var loginEvent = new LoginEvent
{
Ip = appService.RemoteIpAddress,
- Device = appService.UserAgent?.Platform,
+ Device = appService.UserAgent?.Platform ?? "Unknown",
Expire = expire,
SysUser = sysUser,
VerificatId = CommonUtils.GetSingleId()
@@ -156,7 +156,7 @@ public class AdminOAuthHandler(
//生成verificat信息
var verificatInfo = new VerificatInfo
{
- Device = loginEvent.Device,
+ Device = loginEvent.Device ?? "Unknown",
Expire = loginEvent.Expire,
VerificatTimeout = tokenTimeout,
Id = loginEvent.VerificatId,
diff --git a/src/Admin/ThingsGateway.Admin.Application/Services/Auth/AuthService.cs b/src/Admin/ThingsGateway.Admin.Application/Services/Auth/AuthService.cs
index e5bc0fade..a5e2dde0f 100644
--- a/src/Admin/ThingsGateway.Admin.Application/Services/Auth/AuthService.cs
+++ b/src/Admin/ThingsGateway.Admin.Application/Services/Auth/AuthService.cs
@@ -235,7 +235,7 @@ public class AuthService : IAuthService
var logingEvent = new LoginEvent
{
Ip = _appService.RemoteIpAddress,
- Device = _appService.UserAgent?.Platform,
+ Device = _appService.UserAgent?.Platform ?? "Unknown",
Expire = expire,
SysUser = sysUser,
VerificatId = verificatId
@@ -344,7 +344,7 @@ public class AuthService : IAuthService
//生成verificat信息
var verificatInfo = new VerificatInfo
{
- Device = loginEvent.Device,
+ Device = loginEvent.Device ?? "Unknown",
Expire = loginEvent.Expire,
VerificatTimeout = tokenTimeout,
Id = loginEvent.VerificatId,
diff --git a/src/Admin/ThingsGateway.Admin.Razor/Util/AdminResourceUtil.cs b/src/Admin/ThingsGateway.Admin.Razor/Util/AdminResourceUtil.cs
index d2590947d..fc4b26597 100644
--- a/src/Admin/ThingsGateway.Admin.Razor/Util/AdminResourceUtil.cs
+++ b/src/Admin/ThingsGateway.Admin.Razor/Util/AdminResourceUtil.cs
@@ -51,7 +51,7 @@ public static class AdminResourceUtil
Target = item.Target.ToString(),
Items = BuildMenuTrees(items, item.Id).ToList()
};
- if(menu.Url.IsNullOrEmpty())
+ if (menu.Url.IsNullOrEmpty())
{
menu.Match = Microsoft.AspNetCore.Components.Routing.NavLinkMatch.Prefix;
}
diff --git a/src/Directory.Build.props b/src/Directory.Build.props
index f26e859f4..3e5aa62a0 100644
--- a/src/Directory.Build.props
+++ b/src/Directory.Build.props
@@ -1,9 +1,9 @@
- 10.11.81
- 10.11.81
- 10.11.81
+ 10.11.83
+ 10.11.83
+ 10.11.83
10.11.6
10.11.6
8.0.20
diff --git a/src/Foundation/ThingsGateway.Foundation/Channel/Extension/ChannelOptionsExtensions.cs b/src/Foundation/ThingsGateway.Foundation/Channel/Extension/ChannelOptionsExtensions.cs
index fb64af98a..6d7cc3cba 100644
--- a/src/Foundation/ThingsGateway.Foundation/Channel/Extension/ChannelOptionsExtensions.cs
+++ b/src/Foundation/ThingsGateway.Foundation/Channel/Extension/ChannelOptionsExtensions.cs
@@ -8,8 +8,6 @@
// QQ群:605534569
//------------------------------------------------------------------------------
-using System.Buffers;
-
using ThingsGateway.Foundation.Extension.String;
using TouchSocket.SerialPorts;
@@ -101,6 +99,22 @@ public static class ChannelOptionsExtensions
if (channelOptions.MaxClientCount > 0)
config.SetMaxCount(channelOptions.MaxClientCount);
+ // config.SetTransportOption(new TransportOption()
+ // {
+ // MaxBufferSize = 1024,
+ // MinBufferSize = 512,
+ // SendPipeOptions = new System.IO.Pipelines.PipeOptions(
+ // minimumSegmentSize: 512,
+ // pauseWriterThreshold: 1024,
+ // resumeWriterThreshold: 512,
+ // useSynchronizationContext: false),
+ // ReceivePipeOptions = new System.IO.Pipelines.PipeOptions(
+ //minimumSegmentSize: 512,
+ // pauseWriterThreshold: 1024,
+ // resumeWriterThreshold: 512,
+ // useSynchronizationContext: false),
+ // });
+
config.SetTransportOption(a =>
{
a.MaxBufferSize = 1024;
diff --git a/src/Foundation/ThingsGateway.Foundation/Device/DeviceBase.cs b/src/Foundation/ThingsGateway.Foundation/Device/DeviceBase.cs
index 7e7f69a53..ef65e3a5d 100644
--- a/src/Foundation/ThingsGateway.Foundation/Device/DeviceBase.cs
+++ b/src/Foundation/ThingsGateway.Foundation/Device/DeviceBase.cs
@@ -533,8 +533,6 @@ public abstract class DeviceBase : AsyncAndSyncDisposableObject, IDevice
int timeout = 3000,
CancellationToken cancellationToken = default)
{
-
-
var waitData = clientChannel.WaitHandlePool.GetWaitDataAsync(out var sign);
command.Sign = sign;
WaitLock? waitLock = null;
@@ -554,19 +552,17 @@ public abstract class DeviceBase : AsyncAndSyncDisposableObject, IDevice
if (waitData.Status == WaitDataStatus.Success)
return waitData.CompletedData;
- bool timeoutStatus = false;
-
var reusableTimeout = _reusableTimeouts.Get();
try
{
-
var cts = reusableTimeout.GetTokenSource(timeout, cancellationToken, Channel.ClosedToken);
+
await waitData.WaitAsync(cts.Token).ConfigureAwait(false);
+
}
catch (OperationCanceledException)
{
- timeoutStatus = reusableTimeout.TimeoutStatus;
- return timeoutStatus
+ return reusableTimeout.TimeoutStatus
? new MessageBase(new TimeoutException()) { ErrorMessage = $"Timeout, sign: {sign}" }
: new MessageBase(new OperationCanceledException());
}
@@ -577,7 +573,6 @@ public abstract class DeviceBase : AsyncAndSyncDisposableObject, IDevice
finally
{
reusableTimeout.Set();
- timeoutStatus = reusableTimeout.TimeoutStatus;
_reusableTimeouts.Return(reusableTimeout);
}
@@ -587,7 +582,7 @@ public abstract class DeviceBase : AsyncAndSyncDisposableObject, IDevice
}
else
{
- var operResult = waitData.Check(timeoutStatus);
+ var operResult = waitData.Check(reusableTimeout.TimeoutStatus);
return new MessageBase(operResult) { ErrorMessage = $"{operResult.ErrorMessage}, sign: {sign}" };
}
}
diff --git a/src/Gateway/ThingsGateway.Gateway.Application/GlobalData/GlobalData.cs b/src/Gateway/ThingsGateway.Gateway.Application/GlobalData/GlobalData.cs
index 3b25baf21..91d89b8f9 100644
--- a/src/Gateway/ThingsGateway.Gateway.Application/GlobalData/GlobalData.cs
+++ b/src/Gateway/ThingsGateway.Gateway.Application/GlobalData/GlobalData.cs
@@ -259,7 +259,15 @@ public static class GlobalData
}
return false;
}
-
+ public static bool IsRedundantEnable(long deviceId)
+ {
+ if (GlobalData.IdDevices.TryGetValue(deviceId, out var deviceRuntime))
+ {
+ if (deviceRuntime.RedundantEnable && deviceRuntime.RedundantDeviceId != null)
+ return true;
+ }
+ return false;
+ }
public static IEnumerable GetEnableVariables()
{
return IdVariables.Where(a => a.Value.DeviceRuntime?.Enable != false && a.Value.DeviceRuntime?.ChannelRuntime?.Enable != false && a.Value?.Enable == true).Select(a => a.Value);
diff --git a/src/Gateway/ThingsGateway.Gateway.Application/Services/Device/DeviceService.cs b/src/Gateway/ThingsGateway.Gateway.Application/Services/Device/DeviceService.cs
index a40ae99ec..d1b3710ea 100644
--- a/src/Gateway/ThingsGateway.Gateway.Application/Services/Device/DeviceService.cs
+++ b/src/Gateway/ThingsGateway.Gateway.Application/Services/Device/DeviceService.cs
@@ -267,7 +267,7 @@ internal sealed class DeviceService : BaseService, IDeviceService
else
ManageHelper.CheckDeviceCount(1);
- if (input.RedundantEnable && GlobalData.IsRedundant(input.RedundantDeviceId ?? 0))
+ if (input.RedundantEnable && GlobalData.IsRedundantEnable(input.RedundantDeviceId ?? 0))
throw Oops.Bah($"Redundancy configuration error, backup device has been planned into another redundancy group");
if (await base.SaveAsync(input, type).ConfigureAwait(false))
diff --git a/src/Gateway/ThingsGateway.Gateway.Razor/Pages/GatewayMonitorPage/ChannelDeviceTree.razor.cs b/src/Gateway/ThingsGateway.Gateway.Razor/Pages/GatewayMonitorPage/ChannelDeviceTree.razor.cs
index e046a6643..ac6978878 100644
--- a/src/Gateway/ThingsGateway.Gateway.Razor/Pages/GatewayMonitorPage/ChannelDeviceTree.razor.cs
+++ b/src/Gateway/ThingsGateway.Gateway.Razor/Pages/GatewayMonitorPage/ChannelDeviceTree.razor.cs
@@ -13,7 +13,6 @@ using Microsoft.AspNetCore.Components.Web;
using ThingsGateway.Admin.Application;
using ThingsGateway.Admin.Razor;
-using ThingsGateway.NewLife;
using ThingsGateway.NewLife.Extension;
using ThingsGateway.NewLife.Json.Extension;
using ThingsGateway.SqlSugar;
diff --git a/src/Plugin/ThingsGateway.Foundation.Benchmark/Benchmark/ModbusBenchmark.cs b/src/Plugin/ThingsGateway.Foundation.Benchmark/Benchmark/ModbusBenchmark.cs
index 2d0dc484e..45dd902be 100644
--- a/src/Plugin/ThingsGateway.Foundation.Benchmark/Benchmark/ModbusBenchmark.cs
+++ b/src/Plugin/ThingsGateway.Foundation.Benchmark/Benchmark/ModbusBenchmark.cs
@@ -34,8 +34,8 @@ namespace ThingsGateway.Foundation;
public class ModbusBenchmark : IDisposable
{
public static int ClientCount = 1;
- public static int TaskNumberOfItems = 4;
- public static int NumberOfItems = 40;
+ public static int TaskNumberOfItems = 1;
+ public static int NumberOfItems = 1000;
private readonly List _lgbModbusClients = [];
private List thingsgatewaymodbuss = new();
diff --git a/src/Plugin/ThingsGateway.Foundation.Benchmark/Benchmark/S7Benchmark.cs b/src/Plugin/ThingsGateway.Foundation.Benchmark/Benchmark/S7Benchmark.cs
index a9764088a..76d880426 100644
--- a/src/Plugin/ThingsGateway.Foundation.Benchmark/Benchmark/S7Benchmark.cs
+++ b/src/Plugin/ThingsGateway.Foundation.Benchmark/Benchmark/S7Benchmark.cs
@@ -10,7 +10,6 @@
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Diagnosers;
-using BenchmarkDotNet.Jobs;
using HslCommunication.Profinet.Siemens;
diff --git a/src/Plugin/ThingsGateway.Foundation.OpcUa/OpcUaMaster/OpcUaMaster.cs b/src/Plugin/ThingsGateway.Foundation.OpcUa/OpcUaMaster/OpcUaMaster.cs
index 27cf31297..c775955b0 100644
--- a/src/Plugin/ThingsGateway.Foundation.OpcUa/OpcUaMaster/OpcUaMaster.cs
+++ b/src/Plugin/ThingsGateway.Foundation.OpcUa/OpcUaMaster/OpcUaMaster.cs
@@ -837,10 +837,16 @@ public class OpcUaMaster : IAsyncDisposable
{
foreach (var value in monitoreditem.DequeueValues())
{
- var variableNode = ReadNode(monitoreditem.StartNodeId.ToString(), false, StatusCode.IsGood(value.StatusCode)).GetAwaiter().GetResult();
+ var variableNode = ReadNode(monitoreditem.StartNodeId.ToString(), false, StatusCode.IsGood(value.StatusCode)).GetAwaiter().GetResult();
if (value.Value != null)
{
+ if (value.Value.GetType().IsRichPrimitive())
+ {
+ DataChangedHandler?.Invoke((variableNode, monitoreditem, value, null));
+ continue;
+ }
+
var data = JsonUtils.Encode(m_session.MessageContext, TypeInfo.GetBuiltInType(variableNode.DataType, m_session.SystemContext.TypeTable), value.Value);
if (data == null && value.Value != null)
{
diff --git a/src/Plugin/ThingsGateway.Foundation.OpcUa/Utils/CollectionExtension.cs b/src/Plugin/ThingsGateway.Foundation.OpcUa/Utils/CollectionExtension.cs
index 27b4626d6..957b8ded9 100644
--- a/src/Plugin/ThingsGateway.Foundation.OpcUa/Utils/CollectionExtension.cs
+++ b/src/Plugin/ThingsGateway.Foundation.OpcUa/Utils/CollectionExtension.cs
@@ -12,6 +12,38 @@ namespace ThingsGateway.Foundation.OpcUa;
internal static class CollectionExtension
{
+ ///
+ /// 判断是否是元组类型
+ ///
+ /// 类型
+ ///
+ internal static bool IsValueTuple(this Type type)
+ {
+ return type.Namespace == "System" && type.Name.Contains("ValueTuple`");
+ }
+ ///
+ /// 判断是否是富基元类型
+ ///
+ /// 类型
+ ///
+ public static bool IsRichPrimitive(this Type? type)
+ {
+ if (type == null) return false;
+
+ // 处理元组类型
+ if (type.IsValueTuple()) return false;
+
+ // 处理数组类型,基元数组类型也可以是基元类型
+ if (type.IsArray) return type.GetElementType()?.IsRichPrimitive() ?? false;
+
+ // 基元类型或值类型或字符串类型
+ if (type.IsPrimitive || type.IsValueType || type == typeof(string)) return true;
+
+ if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) return type.GenericTypeArguments[0].IsRichPrimitive();
+
+ return false;
+ }
+
public static IEnumerable> ChunkBetter(this IEnumerable source, int chunkSize)
{
if (source == null) throw new ArgumentNullException(nameof(source));
diff --git a/src/Plugin/ThingsGateway.Plugin.OpcDa/OpcDaMaster/OpcDaMaster.cs b/src/Plugin/ThingsGateway.Plugin.OpcDa/OpcDaMaster/OpcDaMaster.cs
index 5cd96df86..790b7ff8e 100644
--- a/src/Plugin/ThingsGateway.Plugin.OpcDa/OpcDaMaster/OpcDaMaster.cs
+++ b/src/Plugin/ThingsGateway.Plugin.OpcDa/OpcDaMaster/OpcDaMaster.cs
@@ -206,7 +206,9 @@ public class OpcDaMaster : CollectBase
if (TaskSchedulerLoop?.Stoped == true) return;
if (DisposedValue)
return;
- LogMessage?.Trace($"{ToString()} Change:{Environment.NewLine} {values?.ToSystemTextJsonString()}");
+
+ if (LogMessage.LogLevel <= LogLevel.Trace)
+ LogMessage?.Trace($"{ToString()} Change:{Environment.NewLine} {values?.ToSystemTextJsonString()}");
foreach (var data in values)
{
@@ -215,11 +217,13 @@ public class OpcDaMaster : CollectBase
if (TaskSchedulerLoop?.Stoped == true) return;
if (DisposedValue)
return;
- var type = data.Value.GetType();
- if (data.Value is Array)
- {
- type = type.GetElementType();
- }
+
+ //var type = data.Value.GetType();
+ //if (data.Value is Array)
+ //{
+ // type = type.GetElementType();
+ //}
+
if (!VariableAddresDicts.TryGetValue(data.Name, out var itemReads)) return;
foreach (var item in itemReads)
diff --git a/src/Plugin/ThingsGateway.Plugin.OpcUa/OpcUaMaster/OpcUaMaster.cs b/src/Plugin/ThingsGateway.Plugin.OpcUa/OpcUaMaster/OpcUaMaster.cs
index 64098f095..1dab1361d 100644
--- a/src/Plugin/ThingsGateway.Plugin.OpcUa/OpcUaMaster/OpcUaMaster.cs
+++ b/src/Plugin/ThingsGateway.Plugin.OpcUa/OpcUaMaster/OpcUaMaster.cs
@@ -164,8 +164,10 @@ public class OpcUaMaster : CollectBase
//如果是订阅模式,连接时添加订阅组
if (_plc.OpcUaProperty?.ActiveSubscribe == true && CurrentDevice.VariableSourceReads.Count > 0 && _plc.Session.SubscriptionCount < CurrentDevice.VariableSourceReads.Count)
{
+ if (cancellationToken.IsCancellationRequested) return;
foreach (var variableSourceRead in CurrentDevice.VariableSourceReads)
{
+ if (cancellationToken.IsCancellationRequested) return;
try
{
if (_plc.Session.Subscriptions.FirstOrDefault(a => a.DisplayName == variableSourceRead.RegisterAddress) == null)
@@ -186,8 +188,8 @@ public class OpcUaMaster : CollectBase
checkLog = false;
}
- LogMessage?.LogInformation("AddSubscriptions done");
}
+ LogMessage?.LogInformation("AddSubscriptions done");
}
}
}
@@ -329,6 +331,7 @@ public class OpcUaMaster : CollectBase
private void DataChangedHandler((Opc.Ua.VariableNode variableNode, MonitoredItem monitoredItem, DataValue dataValue, JToken jToken) data)
{
+
DateTime time = DateTime.Now;
try
{
@@ -338,14 +341,15 @@ public class OpcUaMaster : CollectBase
return;
if (TaskSchedulerLoop?.Stoped == true) return;
- LogMessage?.Trace($"Change: {Environment.NewLine} {data.monitoredItem.StartNodeId} : {data.jToken?.ToString()}");
+ if (LogMessage.LogLevel <= LogLevel.Trace)
+ LogMessage?.Trace($"Change: {Environment.NewLine} {data.monitoredItem.StartNodeId} : {data.jToken?.ToString() ?? data.dataValue?.Value?.ToJsonString()}");
//尝试固定点位的数据类型
- var type = TypeInfo.GetSystemType(TypeInfo.GetBuiltInType(data.variableNode.DataType, _plc.Session.SystemContext.TypeTable), data.variableNode.ValueRank);
+ //var type = TypeInfo.GetSystemType(TypeInfo.GetBuiltInType(data.variableNode.DataType, _plc.Session.SystemContext.TypeTable), data.variableNode.ValueRank);
if (!VariableAddresDicts.TryGetValue(data.monitoredItem.StartNodeId.ToString(), out var itemReads)) return;
- object value = data.jToken.GetObjectFromJToken();
+ object value = data.jToken?.GetObjectFromJToken() ?? data.dataValue?.Value;
var isGood = StatusCode.IsGood(data.dataValue.StatusCode);
if (_driverProperties.SourceTimestampEnable)
@@ -382,6 +386,8 @@ public class OpcUaMaster : CollectBase
LogMessage?.LogWarning(ex);
success = false;
}
+
+
}
#endif
diff --git a/src/Plugin/ThingsGateway.Plugin.OpcUa/Pages/OpcUaMaster.razor.cs b/src/Plugin/ThingsGateway.Plugin.OpcUa/Pages/OpcUaMaster.razor.cs
index 59263bcad..facc425fa 100644
--- a/src/Plugin/ThingsGateway.Plugin.OpcUa/Pages/OpcUaMaster.razor.cs
+++ b/src/Plugin/ThingsGateway.Plugin.OpcUa/Pages/OpcUaMaster.razor.cs
@@ -100,7 +100,7 @@ public partial class OpcUaMaster : IAsyncDisposable
LogMessage?.AddLogger(logger);
_plc.LogEvent = (a, b, c, d) => LogMessage?.Log((LogLevel)a, b, c, d);
- _plc.DataChangedHandler += (a) => LogMessage?.Trace($"id:{a.monitoredItem?.StartNodeId};stateCode:{a.dataValue?.StatusCode};value:{a.jToken?.ToString()}");
+ _plc.DataChangedHandler += (a) => LogMessage?.Trace($"id:{a.monitoredItem?.StartNodeId};stateCode:{a.dataValue?.StatusCode};value:{a.jToken?.ToString() ?? a.dataValue?.Value?.ToJsonString()}");
base.OnInitialized();
}