This commit is contained in:
2248356998 qq.com
2025-09-30 15:25:15 +08:00
parent 2522333a9c
commit 556819c90c
17 changed files with 102 additions and 37 deletions

View File

@@ -45,6 +45,7 @@ public class VerificatInfo : PrimaryIdEntity
/// 登录IP
/// </summary>
[AutoGenerateColumn(Filterable = true, Sortable = true, Width = 200)]
[SugarColumn(IsNullable = true)]
public string LoginIp { get; set; }
/// <summary>
@@ -78,5 +79,6 @@ public class VerificatInfo : PrimaryIdEntity
/// 登录设备
/// </summary>
[AutoGenerateColumn(Filterable = true, Sortable = true, Width = 100)]
[SugarColumn(IsNullable = true)]
public string Device { get; set; }
}

View File

@@ -145,7 +145,7 @@ public class AdminOAuthHandler<TOptions>(
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<TOptions>(
//生成verificat信息
var verificatInfo = new VerificatInfo
{
Device = loginEvent.Device,
Device = loginEvent.Device ?? "Unknown",
Expire = loginEvent.Expire,
VerificatTimeout = tokenTimeout,
Id = loginEvent.VerificatId,

View File

@@ -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,

View File

@@ -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;
}

View File

@@ -1,9 +1,9 @@
<Project>
<PropertyGroup>
<PluginVersion>10.11.81</PluginVersion>
<ProPluginVersion>10.11.81</ProPluginVersion>
<DefaultVersion>10.11.81</DefaultVersion>
<PluginVersion>10.11.83</PluginVersion>
<ProPluginVersion>10.11.83</ProPluginVersion>
<DefaultVersion>10.11.83</DefaultVersion>
<AuthenticationVersion>10.11.6</AuthenticationVersion>
<SourceGeneratorVersion>10.11.6</SourceGeneratorVersion>
<NET8Version>8.0.20</NET8Version>

View File

@@ -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;

View File

@@ -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}" };
}
}

View File

@@ -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<VariableRuntime> GetEnableVariables()
{
return IdVariables.Where(a => a.Value.DeviceRuntime?.Enable != false && a.Value.DeviceRuntime?.ChannelRuntime?.Enable != false && a.Value?.Enable == true).Select(a => a.Value);

View File

@@ -267,7 +267,7 @@ internal sealed class DeviceService : BaseService<Device>, 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))

View File

@@ -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;

View File

@@ -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<IModbusClient> _lgbModbusClients = [];
private List<ModbusMaster> thingsgatewaymodbuss = new();

View File

@@ -10,7 +10,6 @@
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Diagnosers;
using BenchmarkDotNet.Jobs;
using HslCommunication.Profinet.Siemens;

View File

@@ -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)
{

View File

@@ -12,6 +12,38 @@ namespace ThingsGateway.Foundation.OpcUa;
internal static class CollectionExtension
{
/// <summary>
/// 判断是否是元组类型
/// </summary>
/// <param name="type">类型</param>
/// <returns></returns>
internal static bool IsValueTuple(this Type type)
{
return type.Namespace == "System" && type.Name.Contains("ValueTuple`");
}
/// <summary>
/// 判断是否是富基元类型
/// </summary>
/// <param name="type">类型</param>
/// <returns></returns>
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<List<T>> ChunkBetter<T>(this IEnumerable<T> source, int chunkSize)
{
if (source == null) throw new ArgumentNullException(nameof(source));

View File

@@ -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)

View File

@@ -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

View File

@@ -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();
}