Compare commits
	
		
			6 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					9bb9cd7419 | ||
| 
						 | 
					ba008ef8ba | ||
| 
						 | 
					28b533decf | ||
| 
						 | 
					9ee638c2f1 | ||
| 
						 | 
					d90fdbaf35 | ||
| 
						 | 
					b55e3db736 | 
@@ -38,7 +38,7 @@
 | 
			
		||||
		<PackageReference Include="System.Text.RegularExpressions" Version="4.3.1" />
 | 
			
		||||
		<!--<PackageReference Include="Mapster" Version="7.4.0" />-->
 | 
			
		||||
		<PackageReference Include="MiniProfiler.AspNetCore.Mvc" Version="4.5.4" />
 | 
			
		||||
		<PackageReference Include="Swashbuckle.AspNetCore" Version="9.0.1" />
 | 
			
		||||
		<PackageReference Include="Swashbuckle.AspNetCore" Version="9.0.3" />
 | 
			
		||||
	</ItemGroup>
 | 
			
		||||
 | 
			
		||||
	<ItemGroup Condition=" '$(TargetFramework)' == 'net8.0' ">
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,5 @@
 | 
			
		||||
using System.Collections.Concurrent;
 | 
			
		||||
 | 
			
		||||
using ThingsGateway.NewLife.Collections;
 | 
			
		||||
 | 
			
		||||
namespace ThingsGateway.NewLife.DictionaryExtensions;
 | 
			
		||||
 | 
			
		||||
/// <summary>并发字典扩展</summary>
 | 
			
		||||
@@ -106,58 +104,6 @@ public static class DictionaryExtensions
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 批量出队
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public static IEnumerable<T> ToIEnumerableWithDequeue<TKEY, T>(this ConcurrentDictionary<TKEY, T> values, int maxCount = 0)
 | 
			
		||||
    {
 | 
			
		||||
        if (values.IsEmpty) yield break;
 | 
			
		||||
        if (maxCount <= 0)
 | 
			
		||||
        {
 | 
			
		||||
            maxCount = values.Count;
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            maxCount = Math.Min(maxCount, values.Count);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var keys = values.Keys;
 | 
			
		||||
        foreach (var key in keys)
 | 
			
		||||
        {
 | 
			
		||||
            if (maxCount-- <= 0) break;
 | 
			
		||||
            if (values.TryRemove(key, out var result))
 | 
			
		||||
            {
 | 
			
		||||
                yield return result;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 批量出队
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public static IEnumerable<TKEY> ToIEnumerableWithDequeue<TKEY>(this ConcurrentHashSet<TKEY> values, int maxCount = 0)
 | 
			
		||||
    {
 | 
			
		||||
        if (values.IsEmpty) yield break;
 | 
			
		||||
        if (maxCount <= 0)
 | 
			
		||||
        {
 | 
			
		||||
            maxCount = values.Count;
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            maxCount = Math.Min(maxCount, values.Count);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var keys = values.Keys;
 | 
			
		||||
        foreach (var key in keys)
 | 
			
		||||
        {
 | 
			
		||||
            if (maxCount-- <= 0) break;
 | 
			
		||||
            if (values.TryRemove(key))
 | 
			
		||||
            {
 | 
			
		||||
                yield return key;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 批量出队
 | 
			
		||||
@@ -216,35 +162,9 @@ public static class DictionaryExtensions
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 批量出队
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public static List<TKEY> ToListWithDequeue<TKEY>(this ConcurrentHashSet<TKEY> values, int maxCount = 0)
 | 
			
		||||
    {
 | 
			
		||||
        List<TKEY> result = new();
 | 
			
		||||
        if (values.IsEmpty) return result;
 | 
			
		||||
        if (maxCount <= 0)
 | 
			
		||||
        {
 | 
			
		||||
            maxCount = values.Count;
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            maxCount = Math.Min(maxCount, values.Count);
 | 
			
		||||
        }
 | 
			
		||||
        var keys = values.Keys;
 | 
			
		||||
        foreach (var key in keys)
 | 
			
		||||
        {
 | 
			
		||||
            if (maxCount-- <= 0) break;
 | 
			
		||||
            if (values.TryRemove(key))
 | 
			
		||||
            {
 | 
			
		||||
                result.Add(key);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
   
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,13 +1,13 @@
 | 
			
		||||
<Project>
 | 
			
		||||
 | 
			
		||||
	<PropertyGroup>
 | 
			
		||||
		<PluginVersion>10.9.28</PluginVersion>
 | 
			
		||||
		<ProPluginVersion>10.9.26</ProPluginVersion>
 | 
			
		||||
		<DefaultVersion>10.9.28</DefaultVersion>
 | 
			
		||||
		<AuthenticationVersion>2.9.13</AuthenticationVersion>
 | 
			
		||||
		<SourceGeneratorVersion>10.9.13</SourceGeneratorVersion>
 | 
			
		||||
		<NET8Version>8.0.17</NET8Version>
 | 
			
		||||
		<NET9Version>9.0.6</NET9Version>
 | 
			
		||||
		<PluginVersion>10.9.35</PluginVersion>
 | 
			
		||||
		<ProPluginVersion>10.9.35</ProPluginVersion>
 | 
			
		||||
		<DefaultVersion>10.9.35</DefaultVersion>
 | 
			
		||||
		<AuthenticationVersion>2.9.16</AuthenticationVersion>
 | 
			
		||||
		<SourceGeneratorVersion>10.9.15</SourceGeneratorVersion>
 | 
			
		||||
		<NET8Version>8.0.18</NET8Version>
 | 
			
		||||
		<NET9Version>9.0.7</NET9Version>
 | 
			
		||||
		<SatelliteResourceLanguages>zh-Hans;en-US</SatelliteResourceLanguages>
 | 
			
		||||
	</PropertyGroup>
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -81,6 +81,7 @@ public static class CSharpScriptEngineExtension
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public static T Do<T>(string source, params Assembly[] assemblies) where T : class
 | 
			
		||||
    {
 | 
			
		||||
        if (source.IsNullOrEmpty()) return null;
 | 
			
		||||
        var field = $"{CacheKey}-{source}";
 | 
			
		||||
        var runScript = Instance.Get<T>(field);
 | 
			
		||||
        if (runScript == null)
 | 
			
		||||
 
 | 
			
		||||
@@ -10,8 +10,8 @@
 | 
			
		||||
 | 
			
		||||
	<ItemGroup>
 | 
			
		||||
		<PackageReference Include="Microsoft.Extensions.Localization.Abstractions" Version="$(NET9Version)" />
 | 
			
		||||
		<PackageReference Include="TouchSocket" Version="3.1.11" />
 | 
			
		||||
		<PackageReference Include="TouchSocket.SerialPorts" Version="3.1.11" />
 | 
			
		||||
		<PackageReference Include="TouchSocket" Version="3.1.12" />
 | 
			
		||||
		<PackageReference Include="TouchSocket.SerialPorts" Version="3.1.12" />
 | 
			
		||||
	</ItemGroup>
 | 
			
		||||
 | 
			
		||||
	<ItemGroup>
 | 
			
		||||
 
 | 
			
		||||
@@ -39,7 +39,8 @@ public interface IThingsGatewayBitConverter
 | 
			
		||||
 | 
			
		||||
    [JsonProperty(ItemConverterType = typeof(NewtonsoftEncodingConverter))]
 | 
			
		||||
#endif
 | 
			
		||||
    Encoding Encoding { get; set; }
 | 
			
		||||
    public Encoding? Encoding { get; set; }
 | 
			
		||||
    public Encoding EncodingValue { get; }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 当前的Bcd编码类型
 | 
			
		||||
 
 | 
			
		||||
@@ -29,13 +29,16 @@ public partial class ThingsGatewayBitConverter : IThingsGatewayBitConverter
 | 
			
		||||
 | 
			
		||||
    [System.Text.Json.Serialization.JsonConverter(typeof(EncodingConverter))]
 | 
			
		||||
    [JsonConverter(typeof(NewtonsoftEncodingConverter))]
 | 
			
		||||
    public Encoding Encoding { get; set; } = Encoding.UTF8;
 | 
			
		||||
    public Encoding? Encoding { get; set; }
 | 
			
		||||
#else
 | 
			
		||||
 | 
			
		||||
    [JsonConverter(typeof(NewtonsoftEncodingConverter))]
 | 
			
		||||
    public Encoding Encoding { get; set; } = Encoding.UTF8;
 | 
			
		||||
    public Encoding? Encoding { get; set; }
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    public Encoding EncodingValue => Encoding ?? Encoding.UTF8;
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc/>
 | 
			
		||||
    public DataFormatEnum DataFormat { get; set; }
 | 
			
		||||
 | 
			
		||||
@@ -239,7 +242,7 @@ public partial class ThingsGatewayBitConverter : IThingsGatewayBitConverter
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                byte[] bytes = Encoding.GetBytes(value);
 | 
			
		||||
                byte[] bytes = EncodingValue.GetBytes(value);
 | 
			
		||||
                return IsStringReverseByteWord ? bytes.BytesReverseByWord().ArrayExpandToLength(StringLength.Value) : bytes.ArrayExpandToLength(StringLength.Value);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@@ -252,7 +255,7 @@ public partial class ThingsGatewayBitConverter : IThingsGatewayBitConverter
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                byte[] bytes = Encoding.GetBytes(value);
 | 
			
		||||
                byte[] bytes = EncodingValue.GetBytes(value);
 | 
			
		||||
                return IsStringReverseByteWord ? bytes.BytesReverseByWord() : bytes;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@@ -366,8 +369,8 @@ public partial class ThingsGatewayBitConverter : IThingsGatewayBitConverter
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            return IsStringReverseByteWord ?
 | 
			
		||||
                Encoding.GetString(new ReadOnlySpan<byte>(buffer, offset, len).ToArray().BytesReverseByWord()).TrimEnd().Replace($"\0", "") :
 | 
			
		||||
                Encoding.GetString(buffer, offset, len).TrimEnd().Replace($"\0", "");
 | 
			
		||||
                EncodingValue.GetString(new ReadOnlySpan<byte>(buffer, offset, len).ToArray().BytesReverseByWord()).TrimEnd().Replace($"\0", "") :
 | 
			
		||||
                EncodingValue.GetString(buffer, offset, len).TrimEnd().Replace($"\0", "");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -91,7 +91,7 @@ public class ExecuteScriptNode : TextNode, IActuatorNode, IExexcuteExpressionsBa
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    var exexcuteExpressions = CSharpScriptEngineExtension.Do<IExexcuteExpressions>(text);
 | 
			
		||||
                    exexcuteExpressions.TryDispose();
 | 
			
		||||
                    exexcuteExpressions?.TryDispose();
 | 
			
		||||
                }
 | 
			
		||||
                catch
 | 
			
		||||
                {
 | 
			
		||||
@@ -110,6 +110,10 @@ public class ExecuteScriptNode : TextNode, IActuatorNode, IExexcuteExpressionsBa
 | 
			
		||||
        {
 | 
			
		||||
            Logger?.Trace($"Execute script");
 | 
			
		||||
            var exexcuteExpressions = CSharpScriptEngineExtension.Do<IExexcuteExpressions>(Text);
 | 
			
		||||
            if (exexcuteExpressions == null)
 | 
			
		||||
            {
 | 
			
		||||
                return new OperResult<NodeOutput>("exexcuteExpressions is null");
 | 
			
		||||
            }
 | 
			
		||||
            exexcuteExpressions.Logger = Logger;
 | 
			
		||||
            var data = await exexcuteExpressions.ExecuteAsync(input, cancellationToken).ConfigureAwait(false);
 | 
			
		||||
            return new OperResult<NodeOutput>() { Content = data };
 | 
			
		||||
@@ -125,18 +129,19 @@ public class ExecuteScriptNode : TextNode, IActuatorNode, IExexcuteExpressionsBa
 | 
			
		||||
 | 
			
		||||
    public void Dispose()
 | 
			
		||||
    {
 | 
			
		||||
        if (text.IsNullOrWhiteSpace())
 | 
			
		||||
            return;
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
            var exexcuteExpressions = CSharpScriptEngineExtension.Do<IExexcuteExpressions>(text);
 | 
			
		||||
            exexcuteExpressions.TryDispose();
 | 
			
		||||
        }
 | 
			
		||||
        catch
 | 
			
		||||
        if (!text.IsNullOrWhiteSpace())
 | 
			
		||||
        {
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                var exexcuteExpressions = CSharpScriptEngineExtension.Do<IExexcuteExpressions>(text);
 | 
			
		||||
                exexcuteExpressions.TryDispose();
 | 
			
		||||
            }
 | 
			
		||||
            catch
 | 
			
		||||
            {
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
            CSharpScriptEngineExtension.Remove(text);
 | 
			
		||||
        }
 | 
			
		||||
        CSharpScriptEngineExtension.Remove(text);
 | 
			
		||||
        GC.SuppressFinalize(this);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -10,8 +10,8 @@
 | 
			
		||||
		<PackageReference Include="Riok.Mapperly" Version="4.2.1" ExcludeAssets="runtime" PrivateAssets="all" />
 | 
			
		||||
		<PackageReference Include="Rougamo.Fody" Version="5.0.1" />
 | 
			
		||||
		<PackageReference Include="System.Linq.Async" Version="6.0.3" />
 | 
			
		||||
		<PackageReference Include="TouchSocket.Dmtp" Version="3.1.11" />
 | 
			
		||||
		<PackageReference Include="TouchSocket.WebApi.Swagger" Version="3.1.11" />
 | 
			
		||||
		<PackageReference Include="TouchSocket.Dmtp" Version="3.1.12" />
 | 
			
		||||
		<PackageReference Include="TouchSocket.WebApi.Swagger" Version="3.1.12" />
 | 
			
		||||
		<PackageReference Include="ThingsGateway.Authentication" Version="$(AuthenticationVersion)" />
 | 
			
		||||
		<!--<ProjectReference Include="..\..\PluginPro\ThingsGateway.Authentication\ThingsGateway.Authentication.csproj" />-->
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1419,7 +1419,7 @@ EventCallback.Factory.Create<MouseEventArgs>(this, async e =>
 | 
			
		||||
            {
 | 
			
		||||
                if (item.PluginType == PluginTypeEnum.Collect)
 | 
			
		||||
                    collectChannelDevices.Add(item, new());
 | 
			
		||||
                else if (item.PluginType == PluginTypeEnum.Collect)
 | 
			
		||||
                else if (item.PluginType == PluginTypeEnum.Business)
 | 
			
		||||
                    businessChannelDevices.Add(item, new());
 | 
			
		||||
                else
 | 
			
		||||
                    otherChannelDevices.Add(item, new());
 | 
			
		||||
 
 | 
			
		||||
@@ -8,8 +8,6 @@
 | 
			
		||||
//  QQ群:605534569
 | 
			
		||||
//------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
using System.Text;
 | 
			
		||||
 | 
			
		||||
namespace ThingsGateway.Foundation.SiemensS7;
 | 
			
		||||
 | 
			
		||||
internal static class PackHelper
 | 
			
		||||
@@ -88,7 +86,7 @@ internal static class PackHelper
 | 
			
		||||
 | 
			
		||||
                                    if (s7Address.WStringEnable)
 | 
			
		||||
                                    {
 | 
			
		||||
                                        it.ThingsGatewayBitConverter.Encoding = Encoding.Unicode;
 | 
			
		||||
                                        //it.ThingsGatewayBitConverter.Encoding = Encoding.Unicode;
 | 
			
		||||
                                    }
 | 
			
		||||
                                }
 | 
			
		||||
                                else
 | 
			
		||||
@@ -98,7 +96,7 @@ internal static class PackHelper
 | 
			
		||||
                                        // 字符串在S7中,前四个字节不属于实际内容
 | 
			
		||||
                                        it.Index += 4;
 | 
			
		||||
                                        lastLen = it.ThingsGatewayBitConverter.StringLength.Value + 4;
 | 
			
		||||
                                        it.ThingsGatewayBitConverter.Encoding = Encoding.BigEndianUnicode;
 | 
			
		||||
                                        //it.ThingsGatewayBitConverter.Encoding = Encoding.BigEndianUnicode;
 | 
			
		||||
 | 
			
		||||
                                    }
 | 
			
		||||
                                    else if (it.ThingsGatewayBitConverter.IsVariableStringLength)
 | 
			
		||||
 
 | 
			
		||||
@@ -128,12 +128,12 @@ internal sealed partial class SiemensHelper
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    internal static async ValueTask<OperResult<string>> ReadWStringAsync(SiemensS7Master plc, string address, CancellationToken cancellationToken)
 | 
			
		||||
    internal static async ValueTask<OperResult<string>> ReadWStringAsync(SiemensS7Master plc, string address, Encoding encoding, CancellationToken cancellationToken)
 | 
			
		||||
    {
 | 
			
		||||
        //先读取一次获取长度,再读取实际值
 | 
			
		||||
        if (plc.SiemensS7Type != SiemensTypeEnum.S200Smart)
 | 
			
		||||
        {
 | 
			
		||||
            var encoding = Encoding.BigEndianUnicode;
 | 
			
		||||
            encoding ??= Encoding.BigEndianUnicode;
 | 
			
		||||
            var result1 = await plc.ReadAsync(address, 4, cancellationToken).ConfigureAwait(false);
 | 
			
		||||
            if (!result1.IsSuccess)
 | 
			
		||||
            {
 | 
			
		||||
@@ -155,7 +155,7 @@ internal sealed partial class SiemensHelper
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            var encoding = Encoding.Unicode;
 | 
			
		||||
            encoding ??= Encoding.Unicode;
 | 
			
		||||
            var result1 = await plc.ReadAsync(address, 1, cancellationToken).ConfigureAwait(false);
 | 
			
		||||
            if (!result1.IsSuccess)
 | 
			
		||||
                return new OperResult<string>(result1);
 | 
			
		||||
@@ -171,12 +171,12 @@ internal sealed partial class SiemensHelper
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    internal static async ValueTask<OperResult> WriteWStringAsync(SiemensS7Master plc, string address, string value, CancellationToken cancellationToken = default)
 | 
			
		||||
    internal static async ValueTask<OperResult> WriteWStringAsync(SiemensS7Master plc, string address, string value, Encoding encoding, CancellationToken cancellationToken = default)
 | 
			
		||||
    {
 | 
			
		||||
        value ??= string.Empty;
 | 
			
		||||
        if (plc.SiemensS7Type != SiemensTypeEnum.S200Smart)
 | 
			
		||||
        {
 | 
			
		||||
            byte[] inBytes1 = Encoding.BigEndianUnicode.GetBytes(value);
 | 
			
		||||
            byte[] inBytes1 = (encoding ?? Encoding.BigEndianUnicode).GetBytes(value);
 | 
			
		||||
            var result = await plc.ReadAsync(address, 4, cancellationToken).ConfigureAwait(false);
 | 
			
		||||
            if (!result.IsSuccess) return result;
 | 
			
		||||
            var num = plc.ThingsGatewayBitConverter.ToUInt16(result.Content, 0);
 | 
			
		||||
@@ -189,7 +189,7 @@ internal sealed partial class SiemensHelper
 | 
			
		||||
                inBytes1
 | 
			
		||||
                ), DataTypeEnum.String, cancellationToken).ConfigureAwait(false);
 | 
			
		||||
        }
 | 
			
		||||
        byte[] inBytes2 = Encoding.Unicode.GetBytes(value);
 | 
			
		||||
        byte[] inBytes2 = (encoding ?? Encoding.Unicode).GetBytes(value);
 | 
			
		||||
        return await plc.WriteAsync(address, DataTransUtil.SpliceArray([(byte)value.Length], inBytes2), DataTypeEnum.String, cancellationToken).ConfigureAwait(false);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -569,7 +569,7 @@ public partial class SiemensS7Master : DeviceBase
 | 
			
		||||
            {
 | 
			
		||||
                return new OperResult<string[]>(AppResource.StringLengthReadError);
 | 
			
		||||
            }
 | 
			
		||||
            var result = await SiemensHelper.ReadWStringAsync(this, address, cancellationToken).ConfigureAwait(false);
 | 
			
		||||
            var result = await SiemensHelper.ReadWStringAsync(this, address, bitConverter.Encoding, cancellationToken).ConfigureAwait(false);
 | 
			
		||||
            if (result.IsSuccess)
 | 
			
		||||
            {
 | 
			
		||||
                return OperResult.CreateSuccessResult(new string[] { result.Content });
 | 
			
		||||
@@ -585,7 +585,7 @@ public partial class SiemensS7Master : DeviceBase
 | 
			
		||||
            {
 | 
			
		||||
                return new OperResult<string[]>(AppResource.StringLengthReadError);
 | 
			
		||||
            }
 | 
			
		||||
            var result = await SiemensHelper.ReadStringAsync(this, address, bitConverter.Encoding, cancellationToken).ConfigureAwait(false);
 | 
			
		||||
            var result = await SiemensHelper.ReadStringAsync(this, address, bitConverter.EncodingValue, cancellationToken).ConfigureAwait(false);
 | 
			
		||||
            if (result.IsSuccess)
 | 
			
		||||
            {
 | 
			
		||||
                return OperResult.CreateSuccessResult(new string[] { result.Content });
 | 
			
		||||
@@ -608,11 +608,11 @@ public partial class SiemensS7Master : DeviceBase
 | 
			
		||||
 | 
			
		||||
        if (((S7BitConverter)bitConverter)?.WStringEnable == true)
 | 
			
		||||
        {
 | 
			
		||||
            return SiemensHelper.WriteWStringAsync(this, address, value, cancellationToken);
 | 
			
		||||
            return SiemensHelper.WriteWStringAsync(this, address, value, bitConverter.Encoding, cancellationToken);
 | 
			
		||||
        }
 | 
			
		||||
        if (bitConverter.IsVariableStringLength)
 | 
			
		||||
        {
 | 
			
		||||
            return SiemensHelper.WriteStringAsync(this, address, value, bitConverter.Encoding, cancellationToken);
 | 
			
		||||
            return SiemensHelper.WriteStringAsync(this, address, value, bitConverter.EncodingValue, cancellationToken);
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
 
 | 
			
		||||
@@ -147,9 +147,10 @@ public partial class SqlDBProducer : BusinessBaseWithCacheIntervalVariable, IDBH
 | 
			
		||||
    {
 | 
			
		||||
        if (_driverPropertys.IsReadDB)
 | 
			
		||||
        {
 | 
			
		||||
            var list = RealTimeVariables.ToListWithDequeue();
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                var varLists = RealTimeVariables.ToIEnumerableWithDequeue().Batch(100000);
 | 
			
		||||
                var varLists = list.Batch(100000);
 | 
			
		||||
                foreach (var varList in varLists)
 | 
			
		||||
                {
 | 
			
		||||
                    var result = await UpdateAsync(varList, cancellationToken).ConfigureAwait(false);
 | 
			
		||||
@@ -166,6 +167,11 @@ public partial class SqlDBProducer : BusinessBaseWithCacheIntervalVariable, IDBH
 | 
			
		||||
                if (success)
 | 
			
		||||
                    LogMessage?.LogWarning(ex);
 | 
			
		||||
                success = false;
 | 
			
		||||
 | 
			
		||||
                list.ForEach(variable =>
 | 
			
		||||
                {
 | 
			
		||||
                    RealTimeVariables.AddOrUpdate(variable.Id, variable, (key, oldValue) => variable);
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -172,7 +172,7 @@ public class ModbusSlave : BusinessBase
 | 
			
		||||
                await Task.Delay(10000, cancellationToken).ConfigureAwait(false);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        var list = ModbusVariableQueue.ToIEnumerableKVWithDequeue();
 | 
			
		||||
        var list = ModbusVariableQueue.ToDictWithDequeue();
 | 
			
		||||
        foreach (var item in list)
 | 
			
		||||
        {
 | 
			
		||||
            if (cancellationToken.IsCancellationRequested)
 | 
			
		||||
 
 | 
			
		||||
@@ -8,6 +8,8 @@
 | 
			
		||||
//  QQ群:605534569
 | 
			
		||||
//------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
using BootstrapBlazor.Components;
 | 
			
		||||
 | 
			
		||||
using Newtonsoft.Json.Linq;
 | 
			
		||||
 | 
			
		||||
using Opc.Ua;
 | 
			
		||||
@@ -226,7 +228,7 @@ public class ThingsGatewayNodeManager : CustomNodeManager2
 | 
			
		||||
    /// 更新变量
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="variable"></param>
 | 
			
		||||
    public void UpVariable(VariableRuntime variable)
 | 
			
		||||
    public void UpVariable(VariableBasicData variable)
 | 
			
		||||
    {
 | 
			
		||||
        if (!NodeIdTags.TryGetValue($"{variable.DeviceName}.{variable.Name}", out var uaTag))
 | 
			
		||||
            return;
 | 
			
		||||
@@ -314,6 +316,14 @@ public class ThingsGatewayNodeManager : CustomNodeManager2
 | 
			
		||||
                jToken.CalculateActualValueRank(),
 | 
			
		||||
                jToken
 | 
			
		||||
                );
 | 
			
		||||
            if (dataValue == null)
 | 
			
		||||
            {
 | 
			
		||||
                _businessBase.LogMessage?.LogWarning($"{tag.NodeId} value is null , jToken: {jToken}");
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                _businessBase.LogMessage?.LogTrace($"{tag.NodeId} value {dataValue} , jToken: {jToken}");
 | 
			
		||||
            }
 | 
			
		||||
            newValue = dataValue;
 | 
			
		||||
            success = true;
 | 
			
		||||
        }
 | 
			
		||||
@@ -337,7 +347,6 @@ public class ThingsGatewayNodeManager : CustomNodeManager2
 | 
			
		||||
            else
 | 
			
		||||
                tag.ValueRank = ValueRanks.Scalar;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            var tp = elementType ?? value?.GetType() ?? typeof(string);
 | 
			
		||||
 | 
			
		||||
            tag.DataType = DataNodeType(tp);
 | 
			
		||||
@@ -493,8 +502,18 @@ public class ThingsGatewayNodeManager : CustomNodeManager2
 | 
			
		||||
            UserWriteMask = AttributeWriteMask.DisplayName | AttributeWriteMask.Description,
 | 
			
		||||
            ValueRank = ValueRanks.Scalar,
 | 
			
		||||
            Id = variableRuntime.Id,
 | 
			
		||||
            DataType = DataNodeType(variableRuntime),
 | 
			
		||||
        };
 | 
			
		||||
        var type = DataNodeType(variableRuntime);
 | 
			
		||||
        if (type != null)
 | 
			
		||||
        {
 | 
			
		||||
            variable.DataType = type;
 | 
			
		||||
            variable.IsDataTypeInit = true;
 | 
			
		||||
            var elementType = variableRuntime.Value?.GetType()?.GetElementTypeEx();
 | 
			
		||||
            if (elementType != null)
 | 
			
		||||
                variable.ValueRank = ValueRanks.OneOrMoreDimensions;
 | 
			
		||||
            else
 | 
			
		||||
                variable.ValueRank = ValueRanks.Scalar;
 | 
			
		||||
        }
 | 
			
		||||
        var service = dbDrivers.FirstOrDefault(a => GlobalData.ContainsVariable(a.DeviceId, variableRuntime));
 | 
			
		||||
        var level = ThingsGatewayNodeManager.ProtectTypeTrans(variableRuntime, service != null);
 | 
			
		||||
        variable.AccessLevel = level;
 | 
			
		||||
@@ -940,20 +959,24 @@ public class ThingsGatewayNodeManager : CustomNodeManager2
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="variableRuntime"></param>
 | 
			
		||||
    /// <returns></returns>
 | 
			
		||||
    private NodeId DataNodeType(VariableRuntime variableRuntime)
 | 
			
		||||
    private NodeId? DataNodeType(VariableRuntime variableRuntime)
 | 
			
		||||
    {
 | 
			
		||||
        var str = variableRuntime.GetPropertyValue(_businessBase.DeviceId, nameof(OpcUaServerVariableProperty.DataType)) ?? "";
 | 
			
		||||
        Type tp;
 | 
			
		||||
        if (Enum.TryParse(str, out DataTypeEnum result))
 | 
			
		||||
        {
 | 
			
		||||
            tp = result.GetSystemType();
 | 
			
		||||
            return DataNodeType(tp);
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            tp = variableRuntime.Value?.GetType() ?? variableRuntime.DataType.GetSystemType(); ;
 | 
			
		||||
            tp = variableRuntime.Value?.GetType();
 | 
			
		||||
            if (tp != null)
 | 
			
		||||
            {
 | 
			
		||||
                return DataNodeType(tp);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return DataNodeType(tp);
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -14,9 +14,10 @@ using Microsoft.Extensions.Logging;
 | 
			
		||||
using Opc.Ua;
 | 
			
		||||
using Opc.Ua.Configuration;
 | 
			
		||||
 | 
			
		||||
using System.Collections.Concurrent;
 | 
			
		||||
 | 
			
		||||
using ThingsGateway.Extension.Generic;
 | 
			
		||||
using ThingsGateway.Gateway.Application;
 | 
			
		||||
using ThingsGateway.NewLife.Collections;
 | 
			
		||||
using ThingsGateway.NewLife.DictionaryExtensions;
 | 
			
		||||
 | 
			
		||||
using TouchSocket.Core;
 | 
			
		||||
@@ -43,7 +44,7 @@ public partial class OpcUaServer : BusinessBase
 | 
			
		||||
    protected override BusinessPropertyBase _businessPropertyBase => _driverPropertys;
 | 
			
		||||
 | 
			
		||||
    protected IStringLocalizer Localizer { get; private set; }
 | 
			
		||||
    private ConcurrentHashSet<long> CollectVariableRuntimes { get; set; } = new();
 | 
			
		||||
    private ConcurrentDictionary<long, VariableBasicData> CollectVariableRuntimes { get; set; } = new();
 | 
			
		||||
 | 
			
		||||
    private static readonly string[] separator = new string[] { ";" };
 | 
			
		||||
 | 
			
		||||
@@ -53,9 +54,11 @@ public partial class OpcUaServer : BusinessBase
 | 
			
		||||
        //opcua类库内部有大量缓存,如果刷新变量次数大于一定数量,应该重启服务以防止OOM
 | 
			
		||||
        if (Interlocked.Increment(ref VariableChangedCount) > 100)
 | 
			
		||||
        {
 | 
			
		||||
            await Task.Delay(1000, cancellationToken).ConfigureAwait(false);
 | 
			
		||||
            _ = Task.Run(async () =>
 | 
			
		||||
            {
 | 
			
		||||
                await DeviceThreadManage.RestartDeviceAsync(CurrentDevice, false).ConfigureAwait(false);
 | 
			
		||||
                if (!cancellationToken.IsCancellationRequested)
 | 
			
		||||
                    await DeviceThreadManage.RestartDeviceAsync(CurrentDevice, false).ConfigureAwait(false);
 | 
			
		||||
            }
 | 
			
		||||
            , cancellationToken);
 | 
			
		||||
            return;
 | 
			
		||||
@@ -121,6 +124,7 @@ public partial class OpcUaServer : BusinessBase
 | 
			
		||||
    }
 | 
			
		||||
    private void UaDispose()
 | 
			
		||||
    {
 | 
			
		||||
        ApplicationInstance.MessageDlg = null;
 | 
			
		||||
        m_server?.Stop();
 | 
			
		||||
        m_server?.NodeManager?.SafeDispose();
 | 
			
		||||
        m_server?.SafeDispose();
 | 
			
		||||
@@ -155,7 +159,12 @@ public partial class OpcUaServer : BusinessBase
 | 
			
		||||
    {
 | 
			
		||||
        // 启动服务器。
 | 
			
		||||
        await m_application.CheckApplicationInstanceCertificates(true, 1200, cancellationToken).ConfigureAwait(false);
 | 
			
		||||
 | 
			
		||||
        await m_application.Start(m_server).ConfigureAwait(false);
 | 
			
		||||
        IdVariableRuntimes.ForEach(a =>
 | 
			
		||||
        {
 | 
			
		||||
            VariableValueChange(a.Value, a.Value.AdaptVariableBasicData());
 | 
			
		||||
        });
 | 
			
		||||
        await base.ProtectedStartAsync(cancellationToken).ConfigureAwait(false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -167,10 +176,11 @@ public partial class OpcUaServer : BusinessBase
 | 
			
		||||
            {
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    await Task.Delay(3000, cancellationToken).ConfigureAwait(false);
 | 
			
		||||
                    await Task.Delay(2000, cancellationToken).ConfigureAwait(false);
 | 
			
		||||
                    await m_application.CheckApplicationInstanceCertificates(true, 1200, cancellationToken).ConfigureAwait(false);
 | 
			
		||||
                    await m_application.Start(m_server).ConfigureAwait(false);
 | 
			
		||||
                    connect_success = true;
 | 
			
		||||
                    await Task.Delay(2000, cancellationToken).ConfigureAwait(false);
 | 
			
		||||
                    IdVariableRuntimes.ForEach(a =>
 | 
			
		||||
                    {
 | 
			
		||||
                        VariableValueChange(a.Value, a.Value.AdaptVariableBasicData());
 | 
			
		||||
@@ -191,10 +201,7 @@ public partial class OpcUaServer : BusinessBase
 | 
			
		||||
                {
 | 
			
		||||
                    if (!cancellationToken.IsCancellationRequested)
 | 
			
		||||
                    {
 | 
			
		||||
                        if (IdVariableRuntimes.TryGetValue(item, out var variableRuntime) && variableRuntime != null)
 | 
			
		||||
                        {
 | 
			
		||||
                            m_server?.NodeManager?.UpVariable(variableRuntime);
 | 
			
		||||
                        }
 | 
			
		||||
                        m_server?.NodeManager?.UpVariable(item);
 | 
			
		||||
                    }
 | 
			
		||||
                    else
 | 
			
		||||
                    {
 | 
			
		||||
@@ -407,12 +414,12 @@ public partial class OpcUaServer : BusinessBase
 | 
			
		||||
    }
 | 
			
		||||
    private void VariableValueChange(VariableRuntime variableRuntime, VariableBasicData variableData)
 | 
			
		||||
    {
 | 
			
		||||
        if (CurrentDevice.Pause)
 | 
			
		||||
            return;
 | 
			
		||||
        //if (CurrentDevice.Pause)
 | 
			
		||||
        //    return;
 | 
			
		||||
        if (TaskSchedulerLoop?.Stoped == true) return;
 | 
			
		||||
        if (DisposedValue) return;
 | 
			
		||||
        if (IdVariableRuntimes.ContainsKey(variableData.Id))
 | 
			
		||||
            CollectVariableRuntimes.TryAdd(variableData.Id);
 | 
			
		||||
            CollectVariableRuntimes.AddOrUpdate(variableData.Id, variableData, (a, b) => variableData);
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
<Project>
 | 
			
		||||
 | 
			
		||||
	<ItemGroup>
 | 
			
		||||
		<PackageReference Include="ThingsGateway.Plugin.Synchronization" Version="$(ProPluginVersion)" GeneratePathProperty="true">
 | 
			
		||||
		<PackageReference Include="ThingsGateway.Plugin.SyncBridge" Version="$(ProPluginVersion)" GeneratePathProperty="true">
 | 
			
		||||
			<Private>false</Private>
 | 
			
		||||
			<IncludeAssets> native;</IncludeAssets>
 | 
			
		||||
		</PackageReference>
 | 
			
		||||
@@ -64,7 +64,7 @@
 | 
			
		||||
			<PkgThingsGateway_Plugin_SECSPackageFiles Include="$(PkgThingsGateway_Plugin_SECS)\Content\$(PluginTargetFramework)\**\*.*" />
 | 
			
		||||
			<PkgThingsGateway_Plugin_TS550PackageFiles Include="$(PkgThingsGateway_Plugin_TS550)\Content\$(PluginTargetFramework)\**\*.*" />
 | 
			
		||||
			<PkgThingsGateway_Plugin_VigorPackageFiles Include="$(PkgThingsGateway_Plugin_Vigor)\Content\$(PluginTargetFramework)\**\*.*" />
 | 
			
		||||
			<PkgThingsGateway_Plugin_SynchronizationPackageFiles Include="$(PkgThingsGateway_Plugin_Synchronization)\Content\$(PluginTargetFramework)\**\*.*" />
 | 
			
		||||
			<PkgThingsGateway_Plugin_SyncBridgePackageFiles Include="$(PkgThingsGateway_Plugin_SyncBridge)\Content\$(PluginTargetFramework)\**\*.*" />
 | 
			
		||||
 | 
			
		||||
		</ItemGroup>
 | 
			
		||||
		<PropertyGroup>
 | 
			
		||||
@@ -91,7 +91,7 @@
 | 
			
		||||
		<Copy SourceFiles="@(PkgThingsGateway_Plugin_TS550PackageFiles)" DestinationFolder="$(PluginFolder)ThingsGateway.Plugin.TS550%(RecursiveDir)" />
 | 
			
		||||
		<Copy SourceFiles="@(PkgThingsGateway_Plugin_VigorPackageFiles)" DestinationFolder="$(PluginFolder)ThingsGateway.Plugin.Vigor%(RecursiveDir)" />
 | 
			
		||||
 | 
			
		||||
		<Copy SourceFiles="@(PkgThingsGateway_Plugin_VigorPackageFiles)" DestinationFolder="$(PluginFolder)ThingsGateway.Plugin.Synchronization%(RecursiveDir)" />
 | 
			
		||||
		<Copy SourceFiles="@(PkgThingsGateway_Plugin_SyncBridgePackageFiles)" DestinationFolder="$(PluginFolder)ThingsGateway.Plugin.SyncBridge%(RecursiveDir)" />
 | 
			
		||||
	</Target>
 | 
			
		||||
 | 
			
		||||
</Project>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
<Project>
 | 
			
		||||
 | 
			
		||||
	<ItemGroup>
 | 
			
		||||
		<ProjectReference Include="..\PluginPro\ThingsGateway.Plugin.Synchronization\ThingsGateway.Plugin.Synchronization.csproj" />
 | 
			
		||||
		<ProjectReference Include="..\PluginPro\ThingsGateway.Plugin.SyncBridge\ThingsGateway.Plugin.SyncBridge.csproj" />
 | 
			
		||||
 | 
			
		||||
		<ProjectReference Include="..\PluginPro\ThingsGateway.Plugin.AllenBradleyCip\ThingsGateway.Plugin.AllenBradleyCip.csproj" />
 | 
			
		||||
		<ProjectReference Include="..\PluginPro\ThingsGateway.Plugin.BACnet\ThingsGateway.Plugin.BACnet.csproj" />
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,7 @@
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	<ItemGroup>
 | 
			
		||||
	  <PackageReference Include="TouchSocket.Dmtp" Version="3.1.11" />
 | 
			
		||||
	  <PackageReference Include="TouchSocket.Dmtp" Version="3.1.12" />
 | 
			
		||||
		<PackageReference Include="Riok.Mapperly" Version="4.2.1" ExcludeAssets="runtime" PrivateAssets="all" />
 | 
			
		||||
	</ItemGroup>
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user