mirror of
https://gitee.com/ThingsGateway/ThingsGateway.git
synced 2025-10-23 20:13:22 +08:00
Compare commits
40 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
affe9a44e0 | ||
![]() |
43730fa519 | ||
![]() |
d39aa22b09 | ||
![]() |
e232a6b6ea | ||
![]() |
71ebb36fe9 | ||
![]() |
78a0b86327 | ||
![]() |
2636c16a97 | ||
![]() |
fd77c0242d | ||
![]() |
e74819a900 | ||
![]() |
9b7f696c9b | ||
![]() |
0230d614e7 | ||
![]() |
252d99ad78 | ||
![]() |
1ffc200350 | ||
![]() |
807d89b2b2 | ||
![]() |
4013afa1f1 | ||
![]() |
a580927ceb | ||
![]() |
bf2cf52034 | ||
![]() |
81bb8b7c31 | ||
![]() |
a825007fb5 | ||
![]() |
988124d96a | ||
![]() |
f0de815296 | ||
![]() |
0e2d58c887 | ||
![]() |
b155382626 | ||
![]() |
f362d740af | ||
![]() |
4a85e31a4f | ||
![]() |
302c270ad5 | ||
![]() |
3c1517d0f3 | ||
![]() |
f9fb222044 | ||
![]() |
e8edc02ba3 | ||
![]() |
95a44e3053 | ||
![]() |
74a9fe9a87 | ||
![]() |
4d03f9ea1a | ||
![]() |
67c96ca991 | ||
![]() |
88fb793c68 | ||
![]() |
d6d02d8cc5 | ||
![]() |
c5a3f8e2e3 | ||
![]() |
27e8653a1a | ||
![]() |
863beda82c | ||
![]() |
bac84c3ecd | ||
![]() |
2fca2ad9f8 |
@@ -5,3 +5,99 @@ dotnet_diagnostic.CA1848.severity = none
|
||||
|
||||
# CA2254: 模板应为静态表达式
|
||||
dotnet_diagnostic.CA2254.severity = suggestion
|
||||
|
||||
[*.cs]
|
||||
#### 命名样式 ####
|
||||
|
||||
# 命名规则
|
||||
|
||||
dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion
|
||||
dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface
|
||||
dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i
|
||||
|
||||
dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion
|
||||
dotnet_naming_rule.types_should_be_pascal_case.symbols = types
|
||||
dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case
|
||||
|
||||
dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion
|
||||
dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members
|
||||
dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case
|
||||
|
||||
# 符号规范
|
||||
|
||||
dotnet_naming_symbols.interface.applicable_kinds = interface
|
||||
dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
||||
dotnet_naming_symbols.interface.required_modifiers =
|
||||
|
||||
dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum
|
||||
dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
||||
dotnet_naming_symbols.types.required_modifiers =
|
||||
|
||||
dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
|
||||
dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
||||
dotnet_naming_symbols.non_field_members.required_modifiers =
|
||||
|
||||
# 命名样式
|
||||
|
||||
dotnet_naming_style.begins_with_i.required_prefix = I
|
||||
dotnet_naming_style.begins_with_i.required_suffix =
|
||||
dotnet_naming_style.begins_with_i.word_separator =
|
||||
dotnet_naming_style.begins_with_i.capitalization = pascal_case
|
||||
|
||||
dotnet_naming_style.pascal_case.required_prefix =
|
||||
dotnet_naming_style.pascal_case.required_suffix =
|
||||
dotnet_naming_style.pascal_case.word_separator =
|
||||
dotnet_naming_style.pascal_case.capitalization = pascal_case
|
||||
|
||||
dotnet_naming_style.pascal_case.required_prefix =
|
||||
dotnet_naming_style.pascal_case.required_suffix =
|
||||
dotnet_naming_style.pascal_case.word_separator =
|
||||
dotnet_naming_style.pascal_case.capitalization = pascal_case
|
||||
|
||||
[*.vb]
|
||||
#### 命名样式 ####
|
||||
|
||||
# 命名规则
|
||||
|
||||
dotnet_naming_rule.interface_should_be_以_i_开始.severity = suggestion
|
||||
dotnet_naming_rule.interface_should_be_以_i_开始.symbols = interface
|
||||
dotnet_naming_rule.interface_should_be_以_i_开始.style = 以_i_开始
|
||||
|
||||
dotnet_naming_rule.类型_should_be_帕斯卡拼写法.severity = suggestion
|
||||
dotnet_naming_rule.类型_should_be_帕斯卡拼写法.symbols = 类型
|
||||
dotnet_naming_rule.类型_should_be_帕斯卡拼写法.style = 帕斯卡拼写法
|
||||
|
||||
dotnet_naming_rule.非字段成员_should_be_帕斯卡拼写法.severity = suggestion
|
||||
dotnet_naming_rule.非字段成员_should_be_帕斯卡拼写法.symbols = 非字段成员
|
||||
dotnet_naming_rule.非字段成员_should_be_帕斯卡拼写法.style = 帕斯卡拼写法
|
||||
|
||||
# 符号规范
|
||||
|
||||
dotnet_naming_symbols.interface.applicable_kinds = interface
|
||||
dotnet_naming_symbols.interface.applicable_accessibilities = public, friend, private, protected, protected_friend, private_protected
|
||||
dotnet_naming_symbols.interface.required_modifiers =
|
||||
|
||||
dotnet_naming_symbols.类型.applicable_kinds = class, struct, interface, enum
|
||||
dotnet_naming_symbols.类型.applicable_accessibilities = public, friend, private, protected, protected_friend, private_protected
|
||||
dotnet_naming_symbols.类型.required_modifiers =
|
||||
|
||||
dotnet_naming_symbols.非字段成员.applicable_kinds = property, event, method
|
||||
dotnet_naming_symbols.非字段成员.applicable_accessibilities = public, friend, private, protected, protected_friend, private_protected
|
||||
dotnet_naming_symbols.非字段成员.required_modifiers =
|
||||
|
||||
# 命名样式
|
||||
|
||||
dotnet_naming_style.以_i_开始.required_prefix = I
|
||||
dotnet_naming_style.以_i_开始.required_suffix =
|
||||
dotnet_naming_style.以_i_开始.word_separator =
|
||||
dotnet_naming_style.以_i_开始.capitalization = pascal_case
|
||||
|
||||
dotnet_naming_style.帕斯卡拼写法.required_prefix =
|
||||
dotnet_naming_style.帕斯卡拼写法.required_suffix =
|
||||
dotnet_naming_style.帕斯卡拼写法.word_separator =
|
||||
dotnet_naming_style.帕斯卡拼写法.capitalization = pascal_case
|
||||
|
||||
dotnet_naming_style.帕斯卡拼写法.required_prefix =
|
||||
dotnet_naming_style.帕斯卡拼写法.required_suffix =
|
||||
dotnet_naming_style.帕斯卡拼写法.word_separator =
|
||||
dotnet_naming_style.帕斯卡拼写法.capitalization = pascal_case
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<Version>3.0.0.12</Version>
|
||||
<Version>3.0.0.22</Version>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
|
||||
<Authors>Diego</Authors>
|
||||
|
@@ -101,7 +101,7 @@ public abstract class DriverDebugUIBase : ComponentBase, IDisposable
|
||||
catch (Exception ex)
|
||||
{
|
||||
Messages.Add((LogLevel.Error,
|
||||
$"{DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset)} - 错误:{ex.Message}"));
|
||||
$"{DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset)} - 错误:{ex}"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -126,7 +126,7 @@ public abstract class DriverDebugUIBase : ComponentBase, IDisposable
|
||||
catch (Exception ex)
|
||||
{
|
||||
Messages.Add((LogLevel.Error,
|
||||
$"{DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset)} - 写入前失败:{ex.Message}"));
|
||||
$"{DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset)} - 写入前失败:{ex}"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -49,7 +49,7 @@ public partial class DriverDebugUIPage : DriverDebugUIBase
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Messages.Add((Microsoft.Extensions.Logging.LogLevel.Warning, DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset) + " - " + ex.Message));
|
||||
Messages.Add((Microsoft.Extensions.Logging.LogLevel.Warning, DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset) + " - " + ex));
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -116,16 +116,16 @@
|
||||
|
||||
|
||||
<ItemGroup >
|
||||
<PackageReference Include="ThingsGateway.Foundation.Adapter.DLT645" Version="*" />
|
||||
<!--<PackageReference Include="ThingsGateway.Foundation.Adapter.DLT645" Version="*" />
|
||||
<PackageReference Include="ThingsGateway.Foundation.Adapter.Modbus" Version="*" />
|
||||
<PackageReference Include="ThingsGateway.Foundation.Adapter.OPCDA" Version="*" />
|
||||
<PackageReference Include="ThingsGateway.Foundation.Adapter.OPCUA" Version="*" />
|
||||
<PackageReference Include="ThingsGateway.Foundation.Adapter.Siemens" Version="*" />
|
||||
<!--<ProjectReference Include="..\..\Foundation\ThingsGateway.Foundation.Adapter.DLT645\ThingsGateway.Foundation.Adapter.DLT645.csproj" />
|
||||
<PackageReference Include="ThingsGateway.Foundation.Adapter.Siemens" Version="*" />-->
|
||||
<ProjectReference Include="..\..\Foundation\ThingsGateway.Foundation.Adapter.DLT645\ThingsGateway.Foundation.Adapter.DLT645.csproj" />
|
||||
<ProjectReference Include="..\..\Foundation\ThingsGateway.Foundation.Adapter.Modbus\ThingsGateway.Foundation.Adapter.Modbus.csproj" />
|
||||
<ProjectReference Include="..\..\Foundation\ThingsGateway.Foundation.Adapter.OPCDA\ThingsGateway.Foundation.Adapter.OPCDA.csproj" />
|
||||
<ProjectReference Include="..\..\Foundation\ThingsGateway.Foundation.Adapter.OPCUA\ThingsGateway.Foundation.Adapter.OPCUA.csproj" />
|
||||
<ProjectReference Include="..\..\Foundation\ThingsGateway.Foundation.Adapter.Siemens\ThingsGateway.Foundation.Adapter.Siemens.csproj" />-->
|
||||
<ProjectReference Include="..\..\Foundation\ThingsGateway.Foundation.Adapter.Siemens\ThingsGateway.Foundation.Adapter.Siemens.csproj" />
|
||||
|
||||
</ItemGroup>
|
||||
<ItemGroup >
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<Version>3.0.0.12</Version>
|
||||
<Version>3.0.0.22</Version>
|
||||
<GenerateDocumentationFile>True</GenerateDocumentationFile>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<TargetFrameworks>net45;netstandard2.0;net6.0;net7.0</TargetFrameworks>
|
||||
|
@@ -444,7 +444,7 @@ public class DLT645_2007 : ReadWriteDevicesSerialSessionBase
|
||||
|
||||
if (Station.IsNullOrEmpty()) Station = string.Empty;
|
||||
if (Station.Length < 12) Station = Station.PadLeft(12, '0');
|
||||
string str = $"04000C{(level + 1):D2}";
|
||||
string str = $"04000C{level + 1:D2}";
|
||||
|
||||
var commandResult = DLT645Helper.GetDLT645_2007Command((byte)ControlCode.WritePassword,
|
||||
str.ByHexStringToBytes().Reverse().ToArray()
|
||||
|
@@ -92,15 +92,15 @@ public class DLT645_2007Address : DeviceAddressBase
|
||||
StringBuilder stringGeter = new();
|
||||
if (Station.Length > 0)
|
||||
{
|
||||
stringGeter.Append("s=" + Station.Reverse().ToArray().ToHexString() + ";");
|
||||
stringGeter.Append($"s={Station.Reverse().ToArray().ToHexString()};");
|
||||
}
|
||||
if (DataId.Length > 0)
|
||||
{
|
||||
stringGeter.Append(DataId.Reverse().ToArray().ToHexString() + ";");
|
||||
stringGeter.Append($"{DataId.Reverse().ToArray().ToHexString()};");
|
||||
}
|
||||
if (!Reverse)
|
||||
{
|
||||
stringGeter.Append("s=" + Reverse.ToString() + ";");
|
||||
stringGeter.Append($"s={Reverse.ToString()};");
|
||||
}
|
||||
return stringGeter.ToString();
|
||||
}
|
||||
|
@@ -134,7 +134,7 @@ public class DLT645_2007DataHandleAdapter : ReadWriteDevicesTcpDataHandleAdapter
|
||||
|
||||
if ((response[headCodeIndex + 8] != send[sendHeadCodeIndex + 8] + 0x80))//控制码不符合时,返回错误
|
||||
{
|
||||
request.Message = "返回控制码:" + $"0x{response[headCodeIndex + 8]:X2},请求控制码:" + $"0x{send[sendHeadCodeIndex + 8]:X2},不符合规则";
|
||||
request.Message = $"返回控制码:0x{response[headCodeIndex + 8]:X2},请求控制码:0x{send[sendHeadCodeIndex + 8]:X2},不符合规则";
|
||||
request.ErrorCode = 999;
|
||||
return FilterResult.Success;
|
||||
}
|
||||
@@ -146,7 +146,7 @@ public class DLT645_2007DataHandleAdapter : ReadWriteDevicesTcpDataHandleAdapter
|
||||
{
|
||||
byte byte1 = (byte)(response[headCodeIndex + 10] - 0x33);
|
||||
var error = DLT645Helper.Get2007ErrorMessage(byte1);
|
||||
request.Message = "异常控制码:" + $"0x{response[headCodeIndex + 8]:X2},错误信息:{error}";
|
||||
request.Message = $"异常控制码:0x{response[headCodeIndex + 8]:X2},错误信息:{error}";
|
||||
request.ErrorCode = 999;
|
||||
return FilterResult.Success;
|
||||
}
|
||||
|
@@ -147,15 +147,15 @@ public class ModbusAddress : DeviceAddressBase
|
||||
StringBuilder stringGeter = new();
|
||||
if (Station > 0)
|
||||
{
|
||||
stringGeter.Append("s=" + Station.ToString() + ";");
|
||||
stringGeter.Append($"s={Station.ToString()};");
|
||||
}
|
||||
if (WriteFunction > 0)
|
||||
{
|
||||
stringGeter.Append("w=" + WriteFunction.ToString() + ";");
|
||||
stringGeter.Append($"w={WriteFunction.ToString()};");
|
||||
}
|
||||
if (!string.IsNullOrEmpty(SocketId))
|
||||
{
|
||||
stringGeter.Append("id=" + SocketId + ";");
|
||||
stringGeter.Append($"id={SocketId};");
|
||||
}
|
||||
stringGeter.Append(GetFunctionString(ReadFunction) + (AddressStart + 1).ToString());
|
||||
return stringGeter.ToString();
|
||||
|
@@ -117,7 +117,7 @@ internal class ModbusHelper
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new OperResult<byte[], FilterResult>(ex.Message) { Content2 = FilterResult.Success };
|
||||
return new OperResult<byte[], FilterResult>(ex) { Content2 = FilterResult.Success };
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
@@ -165,7 +165,7 @@ internal class ModbusHelper
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new OperResult<byte[]>(ex.Message);
|
||||
return new OperResult<byte[]>(ex);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
@@ -185,7 +185,7 @@ internal class ModbusHelper
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new OperResult<byte[]>(ex.Message);
|
||||
return new OperResult<byte[]>(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -207,7 +207,7 @@ internal class ModbusHelper
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new OperResult<byte[]>(ex.Message);
|
||||
return new OperResult<byte[]>(ex);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
@@ -244,7 +244,7 @@ internal class ModbusHelper
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new OperResult<byte[]>(ex.Message);
|
||||
return new OperResult<byte[]>(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -296,7 +296,7 @@ internal class ModbusHelper
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new OperResult<byte[]>(ex.Message);
|
||||
return new OperResult<byte[]>(ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -101,62 +101,76 @@ public class ModbusSerialServer : ReadWriteDevicesSerialSessionBase
|
||||
return PackHelper.LoadSourceRead<T, T2>(this, deviceVariables, maxPack);
|
||||
|
||||
}
|
||||
|
||||
EasyLock easyLock = new();
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override OperResult<byte[]> Read(string address, int length, CancellationToken cancellationToken = default)
|
||||
{
|
||||
ModbusAddress mAddress;
|
||||
try
|
||||
{
|
||||
mAddress = ModbusAddress.ParseFrom(address, Station);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new OperResult<byte[]>(ex);
|
||||
}
|
||||
if (MulStation)
|
||||
{
|
||||
Init(mAddress);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Station != mAddress.Station)
|
||||
easyLock.Wait();
|
||||
|
||||
ModbusAddress mAddress;
|
||||
try
|
||||
{
|
||||
return new OperResult<byte[]>("地址错误");
|
||||
mAddress = ModbusAddress.ParseFrom(address, Station);
|
||||
}
|
||||
Init(mAddress);
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new OperResult<byte[]>(ex);
|
||||
}
|
||||
if (MulStation)
|
||||
{
|
||||
Init(mAddress);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Station != mAddress.Station)
|
||||
{
|
||||
return new OperResult<byte[]>("地址错误");
|
||||
}
|
||||
Init(mAddress);
|
||||
|
||||
}
|
||||
|
||||
var ModbusServer01ByteBlock = ModbusServer01ByteBlocks[mAddress.Station];
|
||||
var ModbusServer02ByteBlock = ModbusServer02ByteBlocks[mAddress.Station];
|
||||
var ModbusServer03ByteBlock = ModbusServer03ByteBlocks[mAddress.Station];
|
||||
var ModbusServer04ByteBlock = ModbusServer04ByteBlocks[mAddress.Station];
|
||||
int len = mAddress.ReadFunction == 2 || mAddress.ReadFunction == 1 ? length : length * RegisterByteLength;
|
||||
switch (mAddress.ReadFunction)
|
||||
{
|
||||
case 1:
|
||||
byte[] bytes0 = new byte[len];
|
||||
ModbusServer01ByteBlock.Pos = mAddress.AddressStart;
|
||||
ModbusServer01ByteBlock.Read(bytes0);
|
||||
return OperResult.CreateSuccessResult(bytes0);
|
||||
case 2:
|
||||
byte[] bytes1 = new byte[len];
|
||||
ModbusServer02ByteBlock.Pos = mAddress.AddressStart;
|
||||
ModbusServer02ByteBlock.Read(bytes1);
|
||||
return OperResult.CreateSuccessResult(bytes1);
|
||||
case 3:
|
||||
|
||||
byte[] bytes3 = new byte[len];
|
||||
ModbusServer03ByteBlock.Pos = mAddress.AddressStart * RegisterByteLength;
|
||||
ModbusServer03ByteBlock.Read(bytes3);
|
||||
return OperResult.CreateSuccessResult(bytes3);
|
||||
case 4:
|
||||
byte[] bytes4 = new byte[len];
|
||||
ModbusServer04ByteBlock.Pos = mAddress.AddressStart * RegisterByteLength;
|
||||
ModbusServer04ByteBlock.Read(bytes4);
|
||||
return OperResult.CreateSuccessResult(bytes4);
|
||||
}
|
||||
return new OperResult<byte[]>("功能码错误");
|
||||
}
|
||||
|
||||
var ModbusServer01ByteBlock = ModbusServer01ByteBlocks[mAddress.Station];
|
||||
var ModbusServer02ByteBlock = ModbusServer02ByteBlocks[mAddress.Station];
|
||||
var ModbusServer03ByteBlock = ModbusServer03ByteBlocks[mAddress.Station];
|
||||
var ModbusServer04ByteBlock = ModbusServer04ByteBlocks[mAddress.Station];
|
||||
int len = mAddress.ReadFunction == 2 || mAddress.ReadFunction == 1 ? length : length * RegisterByteLength;
|
||||
switch (mAddress.ReadFunction)
|
||||
finally
|
||||
{
|
||||
case 1:
|
||||
byte[] bytes0 = new byte[len];
|
||||
ModbusServer01ByteBlock.Pos = mAddress.AddressStart;
|
||||
ModbusServer01ByteBlock.Read(bytes0);
|
||||
return OperResult.CreateSuccessResult(bytes0);
|
||||
case 2:
|
||||
byte[] bytes1 = new byte[len];
|
||||
ModbusServer02ByteBlock.Pos = mAddress.AddressStart;
|
||||
ModbusServer02ByteBlock.Read(bytes1);
|
||||
return OperResult.CreateSuccessResult(bytes1);
|
||||
case 3:
|
||||
|
||||
byte[] bytes3 = new byte[len];
|
||||
ModbusServer03ByteBlock.Pos = mAddress.AddressStart * RegisterByteLength;
|
||||
ModbusServer03ByteBlock.Read(bytes3);
|
||||
return OperResult.CreateSuccessResult(bytes3);
|
||||
case 4:
|
||||
byte[] bytes4 = new byte[len];
|
||||
ModbusServer04ByteBlock.Pos = mAddress.AddressStart * RegisterByteLength;
|
||||
ModbusServer04ByteBlock.Read(bytes4);
|
||||
return OperResult.CreateSuccessResult(bytes4);
|
||||
easyLock.Release();
|
||||
}
|
||||
return new OperResult<byte[]>("功能码错误");
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
@@ -173,87 +187,108 @@ public class ModbusSerialServer : ReadWriteDevicesSerialSessionBase
|
||||
SerialSession.SetDataHandlingAdapter(dataHandleAdapter);
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override OperResult Write(string address, byte[] value, CancellationToken cancellationToken = default)
|
||||
{
|
||||
ModbusAddress mAddress;
|
||||
try
|
||||
{
|
||||
mAddress = ModbusAddress.ParseFrom(address, Station);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new OperResult(ex);
|
||||
}
|
||||
if (MulStation)
|
||||
{
|
||||
Init(mAddress);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Station != mAddress.Station)
|
||||
easyLock.Wait();
|
||||
ModbusAddress mAddress;
|
||||
try
|
||||
{
|
||||
return new OperResult("地址错误");
|
||||
mAddress = ModbusAddress.ParseFrom(address, Station);
|
||||
}
|
||||
Init(mAddress);
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new OperResult(ex);
|
||||
}
|
||||
if (MulStation)
|
||||
{
|
||||
Init(mAddress);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Station != mAddress.Station)
|
||||
{
|
||||
return new OperResult("地址错误");
|
||||
}
|
||||
Init(mAddress);
|
||||
}
|
||||
var ModbusServer03ByteBlock = ModbusServer03ByteBlocks[mAddress.Station];
|
||||
var ModbusServer04ByteBlock = ModbusServer04ByteBlocks[mAddress.Station];
|
||||
switch (mAddress.ReadFunction)
|
||||
{
|
||||
case 3:
|
||||
ModbusServer03ByteBlock.Pos = mAddress.AddressStart * RegisterByteLength;
|
||||
ModbusServer03ByteBlock.Write(value);
|
||||
return OperResult.CreateSuccessResult();
|
||||
case 4:
|
||||
ModbusServer04ByteBlock.Pos = mAddress.AddressStart * RegisterByteLength;
|
||||
ModbusServer04ByteBlock.Write(value);
|
||||
return OperResult.CreateSuccessResult();
|
||||
}
|
||||
return new OperResult("功能码错误");
|
||||
|
||||
}
|
||||
var ModbusServer03ByteBlock = ModbusServer03ByteBlocks[mAddress.Station];
|
||||
var ModbusServer04ByteBlock = ModbusServer04ByteBlocks[mAddress.Station];
|
||||
switch (mAddress.ReadFunction)
|
||||
finally
|
||||
{
|
||||
case 3:
|
||||
ModbusServer03ByteBlock.Pos = mAddress.AddressStart * RegisterByteLength;
|
||||
ModbusServer03ByteBlock.Write(value);
|
||||
return OperResult.CreateSuccessResult();
|
||||
case 4:
|
||||
ModbusServer04ByteBlock.Pos = mAddress.AddressStart * RegisterByteLength;
|
||||
ModbusServer04ByteBlock.Write(value);
|
||||
return OperResult.CreateSuccessResult();
|
||||
|
||||
easyLock.Release();
|
||||
}
|
||||
return new OperResult("功能码错误");
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override OperResult Write(string address, bool[] value, CancellationToken cancellationToken = default)
|
||||
{
|
||||
ModbusAddress mAddress;
|
||||
try
|
||||
{
|
||||
mAddress = ModbusAddress.ParseFrom(address, Station);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return (new OperResult(ex));
|
||||
}
|
||||
if (MulStation)
|
||||
{
|
||||
Init(mAddress);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Station != mAddress.Station)
|
||||
easyLock.Wait();
|
||||
ModbusAddress mAddress;
|
||||
try
|
||||
{
|
||||
return (new OperResult("地址错误"));
|
||||
mAddress = ModbusAddress.ParseFrom(address, Station);
|
||||
}
|
||||
Init(mAddress);
|
||||
catch (Exception ex)
|
||||
{
|
||||
return (new OperResult(ex));
|
||||
}
|
||||
if (MulStation)
|
||||
{
|
||||
Init(mAddress);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Station != mAddress.Station)
|
||||
{
|
||||
return (new OperResult("地址错误"));
|
||||
}
|
||||
Init(mAddress);
|
||||
|
||||
}
|
||||
|
||||
var ModbusServer01ByteBlock = ModbusServer01ByteBlocks[mAddress.Station];
|
||||
var ModbusServer02ByteBlock = ModbusServer02ByteBlocks[mAddress.Station];
|
||||
switch (mAddress.ReadFunction)
|
||||
{
|
||||
case 1:
|
||||
ModbusServer01ByteBlock.Pos = mAddress.AddressStart;
|
||||
ModbusServer01ByteBlock.Write(value.BoolArrayToByte());
|
||||
return (OperResult.CreateSuccessResult());
|
||||
case 2:
|
||||
ModbusServer02ByteBlock.Pos = mAddress.AddressStart;
|
||||
ModbusServer02ByteBlock.Write(value.BoolArrayToByte());
|
||||
return (OperResult.CreateSuccessResult());
|
||||
}
|
||||
return new OperResult("功能码错误");
|
||||
|
||||
}
|
||||
|
||||
var ModbusServer01ByteBlock = ModbusServer01ByteBlocks[mAddress.Station];
|
||||
var ModbusServer02ByteBlock = ModbusServer02ByteBlocks[mAddress.Station];
|
||||
switch (mAddress.ReadFunction)
|
||||
finally
|
||||
{
|
||||
case 1:
|
||||
ModbusServer01ByteBlock.Pos = mAddress.AddressStart;
|
||||
ModbusServer01ByteBlock.Write(value.BoolArrayToByte());
|
||||
return (OperResult.CreateSuccessResult());
|
||||
case 2:
|
||||
ModbusServer02ByteBlock.Pos = mAddress.AddressStart;
|
||||
ModbusServer02ByteBlock.Write(value.BoolArrayToByte());
|
||||
return (OperResult.CreateSuccessResult());
|
||||
|
||||
easyLock.Release();
|
||||
}
|
||||
return new OperResult("功能码错误");
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
@@ -409,13 +444,9 @@ public class ModbusSerialServer : ReadWriteDevicesSerialSessionBase
|
||||
|
||||
private void Init(ModbusAddress mAddress)
|
||||
{
|
||||
if (ModbusServer01ByteBlocks.TryAdd(mAddress.Station, new(1024 * 128)))
|
||||
ModbusServer01ByteBlocks[mAddress.Station].SetLength(1024 * 128);
|
||||
if (ModbusServer02ByteBlocks.TryAdd(mAddress.Station, new(1024 * 128)))
|
||||
ModbusServer02ByteBlocks[mAddress.Station].SetLength(1024 * 128);
|
||||
if (ModbusServer03ByteBlocks.TryAdd(mAddress.Station, new(1024 * 128)))
|
||||
ModbusServer03ByteBlocks[mAddress.Station].SetLength(1024 * 128);
|
||||
if (ModbusServer04ByteBlocks.TryAdd(mAddress.Station, new(1024 * 128)))
|
||||
ModbusServer04ByteBlocks[mAddress.Station].SetLength(1024 * 128);
|
||||
ModbusServer01ByteBlocks.GetOrAdd(mAddress.Station, a => new ByteBlock(1024 * 128));
|
||||
ModbusServer02ByteBlocks.GetOrAdd(mAddress.Station, a => new ByteBlock(1024 * 128));
|
||||
ModbusServer03ByteBlocks.GetOrAdd(mAddress.Station, a => new ByteBlock(1024 * 128));
|
||||
ModbusServer04ByteBlocks.GetOrAdd(mAddress.Station, a => new ByteBlock(1024 * 128));
|
||||
}
|
||||
}
|
||||
|
@@ -57,7 +57,7 @@ public class ModbusSerialServerDataHandleAdapter : ReadWriteDevicesTcpDataHandle
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new OperResult<byte[]>(ex.Message);
|
||||
return new OperResult<byte[]>(ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -186,7 +186,7 @@ public class ModbusTcpDtu : ReadWriteDevicesTcpServerBase
|
||||
var item = commandResult.Content;
|
||||
if (FrameTime != 0)
|
||||
Thread.Sleep(FrameTime);
|
||||
var WaitingClientEx = client.GetWaitingClient(new() { ThrowBreakException = true });
|
||||
var WaitingClientEx = client.CreateWaitingClient(new() { ThrowBreakException = true });
|
||||
var result = WaitingClientEx.SendThenResponse(item, TimeOut, cancellationToken);
|
||||
return (MessageBase)result.RequestInfo;
|
||||
}
|
||||
@@ -213,7 +213,7 @@ public class ModbusTcpDtu : ReadWriteDevicesTcpServerBase
|
||||
|
||||
var item = commandResult.Content;
|
||||
await Task.Delay(FrameTime, cancellationToken);
|
||||
var WaitingClientEx = client.GetWaitingClient(new() { ThrowBreakException = true });
|
||||
var WaitingClientEx = client.CreateWaitingClient(new() { ThrowBreakException = true });
|
||||
var result = await WaitingClientEx.SendThenResponseAsync(item, TimeOut, cancellationToken);
|
||||
return (MessageBase)result.RequestInfo;
|
||||
}
|
||||
|
@@ -104,62 +104,75 @@ public class ModbusTcpServer : ReadWriteDevicesTcpServerBase
|
||||
return PackHelper.LoadSourceRead<T, T2>(this, deviceVariables, maxPack);
|
||||
|
||||
}
|
||||
|
||||
EasyLock easyLock = new();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override OperResult<byte[]> Read(string address, int length, CancellationToken cancellationToken = default)
|
||||
{
|
||||
ModbusAddress mAddress;
|
||||
try
|
||||
{
|
||||
mAddress = ModbusAddress.ParseFrom(address, Station);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new OperResult<byte[]>(ex);
|
||||
}
|
||||
if (MulStation)
|
||||
{
|
||||
Init(mAddress);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Station != mAddress.Station)
|
||||
easyLock.Wait();
|
||||
|
||||
ModbusAddress mAddress;
|
||||
try
|
||||
{
|
||||
return new OperResult<byte[]>("地址错误");
|
||||
mAddress = ModbusAddress.ParseFrom(address, Station);
|
||||
}
|
||||
Init(mAddress);
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new OperResult<byte[]>(ex);
|
||||
}
|
||||
if (MulStation)
|
||||
{
|
||||
Init(mAddress);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Station != mAddress.Station)
|
||||
{
|
||||
return new OperResult<byte[]>("地址错误");
|
||||
}
|
||||
Init(mAddress);
|
||||
|
||||
}
|
||||
|
||||
var ModbusServer01ByteBlock = ModbusServer01ByteBlocks[mAddress.Station];
|
||||
var ModbusServer02ByteBlock = ModbusServer02ByteBlocks[mAddress.Station];
|
||||
var ModbusServer03ByteBlock = ModbusServer03ByteBlocks[mAddress.Station];
|
||||
var ModbusServer04ByteBlock = ModbusServer04ByteBlocks[mAddress.Station];
|
||||
int len = mAddress.ReadFunction == 2 || mAddress.ReadFunction == 1 ? length : length * RegisterByteLength;
|
||||
switch (mAddress.ReadFunction)
|
||||
{
|
||||
case 1:
|
||||
byte[] bytes0 = new byte[len];
|
||||
ModbusServer01ByteBlock.Pos = mAddress.AddressStart;
|
||||
ModbusServer01ByteBlock.Read(bytes0);
|
||||
return OperResult.CreateSuccessResult(bytes0);
|
||||
case 2:
|
||||
byte[] bytes1 = new byte[len];
|
||||
ModbusServer02ByteBlock.Pos = mAddress.AddressStart;
|
||||
ModbusServer02ByteBlock.Read(bytes1);
|
||||
return OperResult.CreateSuccessResult(bytes1);
|
||||
case 3:
|
||||
|
||||
byte[] bytes3 = new byte[len];
|
||||
ModbusServer03ByteBlock.Pos = mAddress.AddressStart * RegisterByteLength;
|
||||
ModbusServer03ByteBlock.Read(bytes3);
|
||||
return OperResult.CreateSuccessResult(bytes3);
|
||||
case 4:
|
||||
byte[] bytes4 = new byte[len];
|
||||
ModbusServer04ByteBlock.Pos = mAddress.AddressStart * RegisterByteLength;
|
||||
ModbusServer04ByteBlock.Read(bytes4);
|
||||
return OperResult.CreateSuccessResult(bytes4);
|
||||
}
|
||||
return new OperResult<byte[]>("功能码错误");
|
||||
}
|
||||
|
||||
var ModbusServer01ByteBlock = ModbusServer01ByteBlocks[mAddress.Station];
|
||||
var ModbusServer02ByteBlock = ModbusServer02ByteBlocks[mAddress.Station];
|
||||
var ModbusServer03ByteBlock = ModbusServer03ByteBlocks[mAddress.Station];
|
||||
var ModbusServer04ByteBlock = ModbusServer04ByteBlocks[mAddress.Station];
|
||||
int len = mAddress.ReadFunction == 2 || mAddress.ReadFunction == 1 ? length : length * RegisterByteLength;
|
||||
switch (mAddress.ReadFunction)
|
||||
finally
|
||||
{
|
||||
case 1:
|
||||
byte[] bytes0 = new byte[len];
|
||||
ModbusServer01ByteBlock.Pos = mAddress.AddressStart;
|
||||
ModbusServer01ByteBlock.Read(bytes0);
|
||||
return OperResult.CreateSuccessResult(bytes0);
|
||||
case 2:
|
||||
byte[] bytes1 = new byte[len];
|
||||
ModbusServer02ByteBlock.Pos = mAddress.AddressStart;
|
||||
ModbusServer02ByteBlock.Read(bytes1);
|
||||
return OperResult.CreateSuccessResult(bytes1);
|
||||
case 3:
|
||||
|
||||
byte[] bytes3 = new byte[len];
|
||||
ModbusServer03ByteBlock.Pos = mAddress.AddressStart * RegisterByteLength;
|
||||
ModbusServer03ByteBlock.Read(bytes3);
|
||||
return OperResult.CreateSuccessResult(bytes3);
|
||||
case 4:
|
||||
byte[] bytes4 = new byte[len];
|
||||
ModbusServer04ByteBlock.Pos = mAddress.AddressStart * RegisterByteLength;
|
||||
ModbusServer04ByteBlock.Read(bytes4);
|
||||
return OperResult.CreateSuccessResult(bytes4);
|
||||
easyLock.Release();
|
||||
}
|
||||
return new OperResult<byte[]>("功能码错误");
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
@@ -193,84 +206,104 @@ public class ModbusTcpServer : ReadWriteDevicesTcpServerBase
|
||||
/// <inheritdoc/>
|
||||
public override OperResult Write(string address, byte[] value, CancellationToken cancellationToken = default)
|
||||
{
|
||||
ModbusAddress mAddress;
|
||||
try
|
||||
{
|
||||
mAddress = ModbusAddress.ParseFrom(address, Station);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new OperResult(ex);
|
||||
}
|
||||
if (MulStation)
|
||||
{
|
||||
Init(mAddress);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Station != mAddress.Station)
|
||||
easyLock.Wait();
|
||||
ModbusAddress mAddress;
|
||||
try
|
||||
{
|
||||
return new OperResult("地址错误");
|
||||
mAddress = ModbusAddress.ParseFrom(address, Station);
|
||||
}
|
||||
Init(mAddress);
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new OperResult(ex);
|
||||
}
|
||||
if (MulStation)
|
||||
{
|
||||
Init(mAddress);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Station != mAddress.Station)
|
||||
{
|
||||
return new OperResult("地址错误");
|
||||
}
|
||||
Init(mAddress);
|
||||
}
|
||||
var ModbusServer03ByteBlock = ModbusServer03ByteBlocks[mAddress.Station];
|
||||
var ModbusServer04ByteBlock = ModbusServer04ByteBlocks[mAddress.Station];
|
||||
switch (mAddress.ReadFunction)
|
||||
{
|
||||
case 3:
|
||||
ModbusServer03ByteBlock.Pos = mAddress.AddressStart * RegisterByteLength;
|
||||
ModbusServer03ByteBlock.Write(value);
|
||||
return OperResult.CreateSuccessResult();
|
||||
case 4:
|
||||
ModbusServer04ByteBlock.Pos = mAddress.AddressStart * RegisterByteLength;
|
||||
ModbusServer04ByteBlock.Write(value);
|
||||
return OperResult.CreateSuccessResult();
|
||||
}
|
||||
return new OperResult("功能码错误");
|
||||
|
||||
}
|
||||
var ModbusServer03ByteBlock = ModbusServer03ByteBlocks[mAddress.Station];
|
||||
var ModbusServer04ByteBlock = ModbusServer04ByteBlocks[mAddress.Station];
|
||||
switch (mAddress.ReadFunction)
|
||||
finally
|
||||
{
|
||||
case 3:
|
||||
ModbusServer03ByteBlock.Pos = mAddress.AddressStart * RegisterByteLength;
|
||||
ModbusServer03ByteBlock.Write(value);
|
||||
return OperResult.CreateSuccessResult();
|
||||
case 4:
|
||||
ModbusServer04ByteBlock.Pos = mAddress.AddressStart * RegisterByteLength;
|
||||
ModbusServer04ByteBlock.Write(value);
|
||||
return OperResult.CreateSuccessResult();
|
||||
|
||||
easyLock.Release();
|
||||
}
|
||||
return new OperResult("功能码错误");
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override OperResult Write(string address, bool[] value, CancellationToken cancellationToken = default)
|
||||
{
|
||||
ModbusAddress mAddress;
|
||||
try
|
||||
{
|
||||
mAddress = ModbusAddress.ParseFrom(address, Station);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return (new OperResult(ex));
|
||||
}
|
||||
if (MulStation)
|
||||
{
|
||||
Init(mAddress);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Station != mAddress.Station)
|
||||
easyLock.Wait();
|
||||
ModbusAddress mAddress;
|
||||
try
|
||||
{
|
||||
return (new OperResult("地址错误"));
|
||||
mAddress = ModbusAddress.ParseFrom(address, Station);
|
||||
}
|
||||
Init(mAddress);
|
||||
catch (Exception ex)
|
||||
{
|
||||
return (new OperResult(ex));
|
||||
}
|
||||
if (MulStation)
|
||||
{
|
||||
Init(mAddress);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Station != mAddress.Station)
|
||||
{
|
||||
return (new OperResult("地址错误"));
|
||||
}
|
||||
Init(mAddress);
|
||||
|
||||
}
|
||||
|
||||
var ModbusServer01ByteBlock = ModbusServer01ByteBlocks[mAddress.Station];
|
||||
var ModbusServer02ByteBlock = ModbusServer02ByteBlocks[mAddress.Station];
|
||||
switch (mAddress.ReadFunction)
|
||||
{
|
||||
case 1:
|
||||
ModbusServer01ByteBlock.Pos = mAddress.AddressStart;
|
||||
ModbusServer01ByteBlock.Write(value.BoolArrayToByte());
|
||||
return (OperResult.CreateSuccessResult());
|
||||
case 2:
|
||||
ModbusServer02ByteBlock.Pos = mAddress.AddressStart;
|
||||
ModbusServer02ByteBlock.Write(value.BoolArrayToByte());
|
||||
return (OperResult.CreateSuccessResult());
|
||||
}
|
||||
return new OperResult("功能码错误");
|
||||
|
||||
}
|
||||
|
||||
var ModbusServer01ByteBlock = ModbusServer01ByteBlocks[mAddress.Station];
|
||||
var ModbusServer02ByteBlock = ModbusServer02ByteBlocks[mAddress.Station];
|
||||
switch (mAddress.ReadFunction)
|
||||
finally
|
||||
{
|
||||
case 1:
|
||||
ModbusServer01ByteBlock.Pos = mAddress.AddressStart;
|
||||
ModbusServer01ByteBlock.Write(value.BoolArrayToByte());
|
||||
return (OperResult.CreateSuccessResult());
|
||||
case 2:
|
||||
ModbusServer02ByteBlock.Pos = mAddress.AddressStart;
|
||||
ModbusServer02ByteBlock.Write(value.BoolArrayToByte());
|
||||
return (OperResult.CreateSuccessResult());
|
||||
|
||||
easyLock.Release();
|
||||
}
|
||||
return new OperResult("功能码错误");
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
@@ -429,13 +462,9 @@ public class ModbusTcpServer : ReadWriteDevicesTcpServerBase
|
||||
|
||||
private void Init(ModbusAddress mAddress)
|
||||
{
|
||||
if (ModbusServer01ByteBlocks.TryAdd(mAddress.Station, new(1024 * 128)))
|
||||
ModbusServer01ByteBlocks[mAddress.Station].SetLength(1024 * 128);
|
||||
if (ModbusServer02ByteBlocks.TryAdd(mAddress.Station, new(1024 * 128)))
|
||||
ModbusServer02ByteBlocks[mAddress.Station].SetLength(1024 * 128);
|
||||
if (ModbusServer03ByteBlocks.TryAdd(mAddress.Station, new(1024 * 128)))
|
||||
ModbusServer03ByteBlocks[mAddress.Station].SetLength(1024 * 128);
|
||||
if (ModbusServer04ByteBlocks.TryAdd(mAddress.Station, new(1024 * 128)))
|
||||
ModbusServer04ByteBlocks[mAddress.Station].SetLength(1024 * 128);
|
||||
ModbusServer01ByteBlocks.GetOrAdd(mAddress.Station, a => new ByteBlock(1024 * 128));
|
||||
ModbusServer02ByteBlocks.GetOrAdd(mAddress.Station, a => new ByteBlock(1024 * 128));
|
||||
ModbusServer03ByteBlocks.GetOrAdd(mAddress.Station, a => new ByteBlock(1024 * 128));
|
||||
ModbusServer04ByteBlocks.GetOrAdd(mAddress.Station, a => new ByteBlock(1024 * 128));
|
||||
}
|
||||
}
|
||||
|
@@ -57,7 +57,7 @@ public class ModbusTcpServerDataHandleAdapter : ReadWriteDevicesTcpDataHandleAda
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new OperResult<byte[]>(ex.Message);
|
||||
return new OperResult<byte[]>(ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -176,7 +176,7 @@ internal class OpcServer : IDisposable
|
||||
{
|
||||
status = (OPCSERVERSTATUS)o;
|
||||
serverStatus = new();
|
||||
serverStatus.Version = status.wMajorVersion.ToString() + "." + status.wMinorVersion.ToString() + "." + status.wBuildNumber.ToString();
|
||||
serverStatus.Version = $"{status.wMajorVersion.ToString()}.{status.wMinorVersion.ToString()}.{status.wBuildNumber.ToString()}";
|
||||
serverStatus.ServerState = status.dwServerState;
|
||||
serverStatus.StartTime = Comn.Convert.FileTimeToDateTime(status.ftStartTime);
|
||||
serverStatus.CurrentTime = Comn.Convert.FileTimeToDateTime(status.ftCurrentTime);
|
||||
|
@@ -1,4 +1,5 @@
|
||||
#region copyright
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
@@ -8,6 +9,7 @@
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#endregion
|
||||
|
||||
using Newtonsoft.Json.Linq;
|
||||
@@ -17,22 +19,23 @@ using Opc.Ua.Client;
|
||||
using Opc.Ua.Client.ComplexTypes;
|
||||
using Opc.Ua.Configuration;
|
||||
|
||||
|
||||
//修改自https://github.com/dathlin/OpcUaHelper 与OPC基金会net库
|
||||
|
||||
namespace ThingsGateway.Foundation.Adapter.OPCUA;
|
||||
|
||||
/// <summary>
|
||||
/// 订阅委托
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
public delegate void DataChangedEventHandler((VariableNode variableNode, DataValue dataValue, JToken jToken) value);
|
||||
|
||||
/// <summary>
|
||||
/// OPCUAClient
|
||||
/// </summary>
|
||||
public class OPCUAClient : IDisposable
|
||||
{
|
||||
|
||||
#region 属性,变量等
|
||||
|
||||
/// <summary>
|
||||
/// 当前配置
|
||||
/// </summary>
|
||||
@@ -48,30 +51,35 @@ public class OPCUAClient : IDisposable
|
||||
/// </summary>
|
||||
public List<string> Variables = new();
|
||||
|
||||
private readonly Action<byte, object, string, Exception> _logAction;
|
||||
|
||||
/// <summary>
|
||||
/// 当前的变量名称/OPC变量节点
|
||||
/// </summary>
|
||||
private readonly Dictionary<string, VariableNode> _variableDicts = new();
|
||||
|
||||
private readonly object checkLock = new();
|
||||
|
||||
/// <summary>
|
||||
/// 当前的订阅组,组名称/组
|
||||
/// </summary>
|
||||
private readonly Dictionary<string, Subscription> dic_subscriptions = new();
|
||||
|
||||
private readonly ApplicationInstance m_application = new();
|
||||
|
||||
private readonly ApplicationConfiguration m_configuration;
|
||||
private SessionReconnectHandler m_reConnectHandler;
|
||||
private EventHandler m_ReconnectComplete;
|
||||
private EventHandler m_ReconnectStarting;
|
||||
private EventHandler<KeepAliveEventArgs> m_KeepAliveComplete;
|
||||
private EventHandler<bool> m_ConnectComplete;
|
||||
private EventHandler<OpcUaStatusEventArgs> m_OpcStatusChange;
|
||||
|
||||
private ISession m_session;
|
||||
|
||||
/// <summary>
|
||||
/// 默认的构造函数,实例化一个新的OPC UA类
|
||||
/// </summary>
|
||||
public OPCUAClient(Action<byte, object, string, Exception> log)
|
||||
public OPCUAClient()
|
||||
{
|
||||
_logAction = log;
|
||||
var certificateValidator = new CertificateValidator();
|
||||
certificateValidator.CertificateValidation += CertificateValidation;
|
||||
|
||||
@@ -90,7 +98,6 @@ public class OPCUAClient : IDisposable
|
||||
MaxMessageQueueSize = 1000000,
|
||||
MaxNotificationQueueSize = 1000000,
|
||||
MaxPublishRequestCount = 10000000,
|
||||
|
||||
},
|
||||
|
||||
SecurityConfiguration = new SecurityConfiguration
|
||||
@@ -133,8 +140,6 @@ public class OPCUAClient : IDisposable
|
||||
StoreType = CertificateStoreType.Directory,
|
||||
StorePath = AppContext.BaseDirectory + @"OPCUAClientCertificate\pki\trustedUser",
|
||||
}
|
||||
|
||||
|
||||
},
|
||||
|
||||
TransportQuotas = new TransportQuotas
|
||||
@@ -160,8 +165,6 @@ public class OPCUAClient : IDisposable
|
||||
|
||||
m_configuration.Validate(ApplicationType.Client);
|
||||
m_application.ApplicationConfiguration = m_configuration;
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -188,6 +191,52 @@ public class OPCUAClient : IDisposable
|
||||
/// SessionReconnectHandler
|
||||
/// </summary>
|
||||
public SessionReconnectHandler ReConnectHandler => m_reConnectHandler;
|
||||
|
||||
/// <summary>
|
||||
/// Raised when a good keep alive from the server arrives.
|
||||
/// </summary>
|
||||
public event EventHandler<KeepAliveEventArgs> KeepAliveComplete
|
||||
{
|
||||
add { m_KeepAliveComplete += value; }
|
||||
remove { m_KeepAliveComplete -= value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raised when a reconnect operation starts.
|
||||
/// </summary>
|
||||
public event EventHandler ReconnectStarting
|
||||
{
|
||||
add { m_ReconnectStarting += value; }
|
||||
remove { m_ReconnectStarting -= value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raised when a reconnect operation completes.
|
||||
/// </summary>
|
||||
public event EventHandler ReconnectComplete
|
||||
{
|
||||
add { m_ReconnectComplete += value; }
|
||||
remove { m_ReconnectComplete -= value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raised after successfully connecting to or disconnecing from a server.
|
||||
/// </summary>
|
||||
public event EventHandler<bool> ConnectComplete
|
||||
{
|
||||
add { m_ConnectComplete += value; }
|
||||
remove { m_ConnectComplete -= value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raised after the client status change
|
||||
/// </summary>
|
||||
public event EventHandler<OpcUaStatusEventArgs> OpcStatusChange
|
||||
{
|
||||
add { m_OpcStatusChange += value; }
|
||||
remove { m_OpcStatusChange -= value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当前活动会话。
|
||||
/// </summary>
|
||||
@@ -231,7 +280,7 @@ public class OPCUAClient : IDisposable
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logAction?.Invoke(3, this, $"初始化{items[i]}变量订阅失败", ex);
|
||||
UpdateStatus(3, DateTime.Now, $"初始化{items[i]}变量订阅失败,错误原因:{ex}");
|
||||
}
|
||||
}
|
||||
m_subscription.AddItems(monitoredItems);
|
||||
@@ -247,9 +296,9 @@ public class OPCUAClient : IDisposable
|
||||
var isError = m_subscription.MonitoredItems.Any(a => a.Status.Error != null && StatusCode.IsBad(a.Status.Error.StatusCode));
|
||||
if (isError)
|
||||
{
|
||||
_logAction?.Invoke(3, this, $"创建以下变量订阅失败:{Environment.NewLine}{m_subscription.MonitoredItems.Where(
|
||||
UpdateStatus(3, DateTime.Now, $"创建以下变量订阅失败:{Environment.NewLine}{m_subscription.MonitoredItems.Where(
|
||||
a => a.Status.Error != null && StatusCode.IsBad(a.Status.Error.StatusCode))
|
||||
.Select(a => a.StartNodeId.ToString() + ":" + a.Status.Error.ToString()).ToJsonString()}", null);
|
||||
.Select(a => $"{a.StartNodeId.ToString()}:{a.Status.Error.ToString()}").ToJsonString()}");
|
||||
}
|
||||
|
||||
lock (dic_subscriptions)
|
||||
@@ -281,7 +330,6 @@ public class OPCUAClient : IDisposable
|
||||
item.Value.Delete(true);
|
||||
m_session.RemoveSubscription(item.Value);
|
||||
try { item.Value.Dispose(); } catch { }
|
||||
|
||||
}
|
||||
dic_subscriptions.Clear();
|
||||
}
|
||||
@@ -304,39 +352,40 @@ public class OPCUAClient : IDisposable
|
||||
dic_subscriptions.RemoveWhere(a => a.Key == subscriptionName);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void Callback(MonitoredItem monitoreditem, MonitoredItemNotificationEventArgs monitoredItemNotificationEventArgs)
|
||||
{
|
||||
try
|
||||
{
|
||||
var variableNode = ReadNode(monitoreditem.StartNodeId.ToString(), false);
|
||||
foreach (var value in monitoreditem.DequeueValues())
|
||||
if (m_session != null)
|
||||
{
|
||||
if (value.Value != null)
|
||||
var variableNode = ReadNode(monitoreditem.StartNodeId.ToString(), false);
|
||||
foreach (var value in monitoreditem.DequeueValues())
|
||||
{
|
||||
var data = JsonUtils.Encode(m_session.MessageContext, TypeInfo.GetBuiltInType(variableNode.DataType, m_session.SystemContext.TypeTable), value.Value);
|
||||
if (data == null && value.Value != null)
|
||||
if (value.Value != null)
|
||||
{
|
||||
_logAction?.Invoke(3, this, $"{monitoreditem.StartNodeId}转换出错,原始值String为{value.Value}", null);
|
||||
var data1 = JsonUtils.Encode(m_session.MessageContext, TypeInfo.GetBuiltInType(variableNode.DataType, m_session.SystemContext.TypeTable), value.Value);
|
||||
var data = JsonUtils.Encode(m_session.MessageContext, TypeInfo.GetBuiltInType(variableNode.DataType, m_session.SystemContext.TypeTable), value.Value);
|
||||
if (data == null && value.Value != null)
|
||||
{
|
||||
UpdateStatus(3, DateTime.Now, $"{monitoreditem.StartNodeId}转换出错,原始值String为{value.Value}");
|
||||
var data1 = JsonUtils.Encode(m_session.MessageContext, TypeInfo.GetBuiltInType(variableNode.DataType, m_session.SystemContext.TypeTable), value.Value);
|
||||
}
|
||||
DataChangedHandler?.Invoke((variableNode, value, data));
|
||||
}
|
||||
else
|
||||
{
|
||||
var data = JValue.CreateNull();
|
||||
DataChangedHandler?.Invoke((variableNode, value, data));
|
||||
}
|
||||
DataChangedHandler?.Invoke((variableNode, value, data));
|
||||
}
|
||||
else
|
||||
{
|
||||
var data = JValue.CreateNull();
|
||||
DataChangedHandler?.Invoke((variableNode, value, data));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logAction?.Invoke(3, this, $"{monitoreditem.StartNodeId}订阅处理错误", ex);
|
||||
UpdateStatus(3, DateTime.Now, $"{monitoreditem.StartNodeId}订阅处理错误,错误原因:" + ex);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -462,8 +511,8 @@ public class OPCUAClient : IDisposable
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region 连接
|
||||
|
||||
private ComplexTypeSystem typeSystem;
|
||||
|
||||
/// <summary>
|
||||
@@ -472,7 +521,6 @@ public class OPCUAClient : IDisposable
|
||||
public async Task ConnectAsync()
|
||||
{
|
||||
await ConnectAsync(OPCNode.OPCUrl);
|
||||
_logAction?.Invoke(1, this, $"连接成功", null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -484,10 +532,10 @@ public class OPCUAClient : IDisposable
|
||||
// disconnect any existing session.
|
||||
if (m_session != null)
|
||||
{
|
||||
_logAction?.Invoke(1, this, $"主动断开连接", null);
|
||||
m_session = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new session.
|
||||
/// </summary>
|
||||
@@ -516,20 +564,24 @@ public class OPCUAClient : IDisposable
|
||||
//创建本地证书
|
||||
await m_application.CheckApplicationInstanceCertificate(true, 0, 1200);
|
||||
m_session = await Opc.Ua.Client.Session.Create(
|
||||
m_configuration,
|
||||
endpoint,
|
||||
false,
|
||||
OPCNode.CheckDomain,
|
||||
(string.IsNullOrEmpty(OPCUAName)) ? m_configuration.ApplicationName : OPCUAName,
|
||||
60000,
|
||||
userIdentity,
|
||||
Array.Empty<string>());
|
||||
|
||||
m_configuration,
|
||||
endpoint,
|
||||
false,
|
||||
OPCNode.CheckDomain,
|
||||
(string.IsNullOrEmpty(OPCUAName)) ? m_configuration.ApplicationName : OPCUAName,
|
||||
60000,
|
||||
userIdentity,
|
||||
Array.Empty<string>());
|
||||
typeSystem = new ComplexTypeSystem(m_session);
|
||||
|
||||
m_session.KeepAliveInterval = OPCNode.KeepAliveInterval == 0 ? 60000 : OPCNode.KeepAliveInterval;
|
||||
m_session.KeepAlive += new KeepAliveEventHandler(Session_KeepAlive);
|
||||
|
||||
// raise an event.
|
||||
DoConnectComplete(true);
|
||||
|
||||
UpdateStatus(2, DateTime.UtcNow, "Connected");
|
||||
|
||||
//如果是订阅模式,连接时添加订阅组
|
||||
if (OPCNode.ActiveSubscribe)
|
||||
await AddSubscriptionAsync(Guid.NewGuid().ToString(), Variables.ToArray(), OPCNode.LoadType);
|
||||
@@ -538,6 +590,9 @@ public class OPCUAClient : IDisposable
|
||||
|
||||
private void PrivateDisconnect()
|
||||
{
|
||||
bool state = m_session?.Connected == true;
|
||||
|
||||
|
||||
if (m_reConnectHandler != null)
|
||||
{
|
||||
try { m_reConnectHandler.Dispose(); } catch { }
|
||||
@@ -549,8 +604,14 @@ public class OPCUAClient : IDisposable
|
||||
m_session.Close(10000);
|
||||
}
|
||||
|
||||
if (state)
|
||||
{
|
||||
UpdateStatus(2, DateTime.UtcNow, "Disconnected");
|
||||
DoConnectComplete(false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 读取/写入
|
||||
@@ -593,7 +654,6 @@ public class OPCUAClient : IDisposable
|
||||
valuesToWrite.Add(valueToWrite);
|
||||
}
|
||||
|
||||
|
||||
var result = await m_session.WriteAsync(
|
||||
requestHeader: null,
|
||||
nodesToWrite: valuesToWrite, cancellationToken);
|
||||
@@ -601,7 +661,6 @@ public class OPCUAClient : IDisposable
|
||||
ClientBase.ValidateResponse(result.Results, valuesToWrite);
|
||||
ClientBase.ValidateDiagnosticInfos(result.DiagnosticInfos, valuesToWrite);
|
||||
|
||||
|
||||
var keys = writeInfoLists.Keys.ToList();
|
||||
for (int i = 0; i < keys.Count; i++)
|
||||
{
|
||||
@@ -624,7 +683,6 @@ public class OPCUAClient : IDisposable
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -706,7 +764,6 @@ public class OPCUAClient : IDisposable
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 从服务器读取节点
|
||||
/// </summary>
|
||||
@@ -729,18 +786,14 @@ public class OPCUAClient : IDisposable
|
||||
}
|
||||
else
|
||||
{
|
||||
_logAction?.Invoke(3, this, $"获取服务器节点信息失败{nodes.Item2[i]}", null);
|
||||
UpdateStatus(3, DateTime.Now, $"获取服务器节点信息失败{nodes.Item2[i]}");
|
||||
}
|
||||
}
|
||||
return nodes.Item1.ToList();
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region 特性
|
||||
|
||||
/// <summary>
|
||||
@@ -805,7 +858,6 @@ public class OPCUAClient : IDisposable
|
||||
ResultMask = (uint)BrowseResultMask.All
|
||||
};
|
||||
nodesToBrowse.Add(nodeToBrowse);
|
||||
|
||||
}
|
||||
|
||||
return await ReadNoteAttributeAsync(nodesToBrowse, nodesToRead, cancellationToken);
|
||||
@@ -968,11 +1020,9 @@ public class OPCUAClient : IDisposable
|
||||
|
||||
return nodeAttribute.ToArray();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
{
|
||||
@@ -991,7 +1041,6 @@ public class OPCUAClient : IDisposable
|
||||
throw new Exception(string.Format("验证证书失败,错误代码:{0}: {1}", eventArgs.Error.Code, eventArgs.Error.AdditionalInfo));
|
||||
}
|
||||
|
||||
|
||||
private async Task<Dictionary<string, List<OPCNodeAttribute>>> ReadNoteAttributeAsync(BrowseDescriptionCollection nodesToBrowse, ReadValueIdCollection nodesToRead, CancellationToken cancellationToken)
|
||||
{
|
||||
int startOfProperties = nodesToRead.Count;
|
||||
@@ -1068,7 +1117,6 @@ public class OPCUAClient : IDisposable
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (nodeAttributes.ContainsKey(nodeToRead.NodeId.ToString()))
|
||||
{
|
||||
nodeAttributes[nodeToRead.NodeId.ToString()].Add(item);
|
||||
@@ -1086,21 +1134,47 @@ public class OPCUAClient : IDisposable
|
||||
/// </summary>
|
||||
private void Server_ReconnectComplete(object sender, EventArgs e)
|
||||
{
|
||||
if (!Object.ReferenceEquals(sender, m_reConnectHandler))
|
||||
try
|
||||
{
|
||||
return;
|
||||
if (!Object.ReferenceEquals(sender, m_reConnectHandler))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_session = m_reConnectHandler.Session;
|
||||
m_reConnectHandler.Dispose();
|
||||
m_reConnectHandler = null;
|
||||
|
||||
// raise any additional notifications.
|
||||
m_ReconnectComplete?.Invoke(this, e);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
m_session = m_reConnectHandler.Session;
|
||||
m_reConnectHandler = null;
|
||||
|
||||
/// <summary>
|
||||
/// Report the client status
|
||||
/// </summary>
|
||||
/// <param name="logLevel">Whether the status represents an error. </param>
|
||||
/// <param name="time">The time associated with the status.</param>
|
||||
/// <param name="status">The status message.</param>
|
||||
/// <param name="args">Arguments used to format the status message.</param>
|
||||
private void UpdateStatus(int logLevel, DateTime time, string status, params object[] args)
|
||||
{
|
||||
m_OpcStatusChange?.Invoke(this, new OpcUaStatusEventArgs()
|
||||
{
|
||||
LogLevel = logLevel,
|
||||
Time = time.ToLocalTime(),
|
||||
Text = String.Format(status, args),
|
||||
});
|
||||
}
|
||||
|
||||
private void Session_KeepAlive(ISession session, KeepAliveEventArgs e)
|
||||
{
|
||||
lock (checkLock)
|
||||
{
|
||||
|
||||
if (!Object.ReferenceEquals(session, m_session))
|
||||
{
|
||||
return;
|
||||
@@ -1108,22 +1182,39 @@ public class OPCUAClient : IDisposable
|
||||
|
||||
if (ServiceResult.IsBad(e.Status))
|
||||
{
|
||||
_logAction?.Invoke(3, this, $"心跳检测错误:{e.Status}", null);
|
||||
if (m_session.KeepAliveInterval <= 0)
|
||||
{
|
||||
UpdateStatus(3, e.CurrentTime, "Communication Error ({0})", e.Status);
|
||||
return;
|
||||
}
|
||||
|
||||
UpdateStatus(3, e.CurrentTime, "Reconnecting in {0}s", m_session.KeepAliveInterval / 1000);
|
||||
|
||||
if (m_reConnectHandler == null)
|
||||
{
|
||||
m_ReconnectStarting?.Invoke(this, e);
|
||||
|
||||
m_reConnectHandler = new SessionReconnectHandler();
|
||||
m_reConnectHandler.BeginReconnect(m_session, m_session.KeepAliveInterval, Server_ReconnectComplete);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// update status.
|
||||
UpdateStatus(0, e.CurrentTime, "Session_KeepAlive Connected [{0}]", session.Endpoint.EndpointUrl);
|
||||
|
||||
// raise any additional notifications.
|
||||
m_KeepAliveComplete?.Invoke(this, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Raises the connect complete event on the main GUI thread.
|
||||
/// </summary>
|
||||
private void DoConnectComplete(bool state)
|
||||
{
|
||||
m_ConnectComplete?.Invoke(this, state);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
@@ -1,4 +1,5 @@
|
||||
#region copyright
|
||||
#region copyright
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
@@ -8,11 +9,39 @@
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#endregion
|
||||
|
||||
using Opc.Ua;
|
||||
|
||||
namespace ThingsGateway.Foundation.Adapter.OPCUA;
|
||||
|
||||
/// <summary>
|
||||
/// OPC UA的状态更新消息
|
||||
/// </summary>
|
||||
public class OpcUaStatusEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// 日志等级,<br></br>
|
||||
/// 更为详细的步骤型日志输出 Trace = 0,<br></br>
|
||||
/// 调试信息日志Debug = 1,<br></br>
|
||||
/// 消息类日志输出 Info = 2,<br></br>
|
||||
/// 警告类日志输出 Warning = 3,<br></br>
|
||||
/// 错误类日志输出 Error = 4,<br></br>
|
||||
/// 不可控中断类日输出Critical = 5,
|
||||
/// </summary>
|
||||
public int LogLevel { get; set; }
|
||||
/// <summary>
|
||||
/// 时间
|
||||
/// </summary>
|
||||
public DateTime Time { get; set; }
|
||||
/// <summary>
|
||||
/// 文本
|
||||
/// </summary>
|
||||
public string Text { get; set; }
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取属性过程中用于描述的
|
||||
/// </summary>
|
||||
@@ -22,6 +51,7 @@ public class OPCNodeAttribute
|
||||
/// 属性的名称
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 操作结果状态描述
|
||||
/// </summary>
|
||||
@@ -31,10 +61,9 @@ public class OPCNodeAttribute
|
||||
/// 属性的类型描述
|
||||
/// </summary>
|
||||
public string Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 属性的值,如果读取错误,返回文本描述
|
||||
/// </summary>
|
||||
public object Value { get; set; }
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -11,5 +11,4 @@
|
||||
<PackageReference Include="OPCFoundation.NetStandard.Opc.Ua.Client.ComplexTypes" Version="1.4.372.56" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
</Project>
|
||||
|
@@ -250,44 +250,44 @@ public class SiemensAddress : DeviceAddressBase
|
||||
{
|
||||
if (DataCode == (byte)S7Area.TM)
|
||||
{
|
||||
return "T" + Address.ToString() + (IsWString ? ";W=true;" : ";W=false;");
|
||||
return $"T{Address.ToString()}{(IsWString ? ";W=true;" : ";W=false;")}";
|
||||
}
|
||||
if (DataCode == (byte)S7Area.CT)
|
||||
{
|
||||
return "C" + Address.ToString() + (IsWString ? ";W=true;" : ";W=false;");
|
||||
return $"C{Address.ToString()}{(IsWString ? ";W=true;" : ";W=false;")}";
|
||||
}
|
||||
|
||||
if (DataCode == (byte)S7Area.AI)
|
||||
{
|
||||
return "AI" + GetStringAddress(AddressStart) + (IsWString ? ";W=true;" : ";W=false;");
|
||||
return $"AI{GetStringAddress(AddressStart)}{(IsWString ? ";W=true;" : ";W=false;")}";
|
||||
}
|
||||
|
||||
if (DataCode == (byte)S7Area.AQ)
|
||||
{
|
||||
return "AQ" + GetStringAddress(AddressStart) + (IsWString ? ";W=true;" : ";W=false;");
|
||||
return $"AQ{GetStringAddress(AddressStart)}{(IsWString ? ";W=true;" : ";W=false;")}";
|
||||
}
|
||||
|
||||
if (DataCode == (byte)S7Area.PE)
|
||||
{
|
||||
return "I" + GetStringAddress(AddressStart) + (IsWString ? ";W=true;" : ";W=false;");
|
||||
return $"I{GetStringAddress(AddressStart)}{(IsWString ? ";W=true;" : ";W=false;")}";
|
||||
}
|
||||
|
||||
if (DataCode == (byte)S7Area.PA)
|
||||
{
|
||||
return "Q" + GetStringAddress(AddressStart) + (IsWString ? ";W=true;" : ";W=false;");
|
||||
return $"Q{GetStringAddress(AddressStart)}{(IsWString ? ";W=true;" : ";W=false;")}";
|
||||
}
|
||||
|
||||
if (DataCode == (byte)S7Area.MK)
|
||||
{
|
||||
return "M" + GetStringAddress(AddressStart) + (IsWString ? ";W=true;" : ";W=false;");
|
||||
return $"M{GetStringAddress(AddressStart)}{(IsWString ? ";W=true;" : ";W=false;")}";
|
||||
}
|
||||
|
||||
return DataCode == (byte)S7Area.DB ? "DB" + DbBlock.ToString() + "." + GetStringAddress(AddressStart) + (IsWString ? ";W=true;" : ";W=false;") : Address.ToString() + (IsWString ? ";W=true;" : ";W=false;");
|
||||
return DataCode == (byte)S7Area.DB ? $"DB{DbBlock.ToString()}.{GetStringAddress(AddressStart)}{(IsWString ? ";W=true;" : ";W=false;")}" : Address.ToString() + (IsWString ? ";W=true;" : ";W=false;");
|
||||
}
|
||||
|
||||
private static string GetStringAddress(int addressStart)
|
||||
{
|
||||
return addressStart % 8 == 0 ? (addressStart / 8).ToString() : string.Format("{0}.{1}", addressStart / 8, addressStart % 8);
|
||||
return addressStart % 8 == 0 ? (addressStart / 8).ToString() : $"{addressStart / 8}.{addressStart % 8}";
|
||||
}
|
||||
|
||||
}
|
@@ -24,7 +24,7 @@ public abstract class ReadWriteDevicesSerialSessionBase : ReadWriteDevicesBase
|
||||
public ReadWriteDevicesSerialSessionBase(SerialSession serialSession)
|
||||
{
|
||||
SerialSession = serialSession;
|
||||
WaitingClientEx = SerialSession.GetWaitingClient(new() { ThrowBreakException = true });
|
||||
WaitingClientEx = SerialSession.CreateWaitingClient(new() { ThrowBreakException = true });
|
||||
SerialSession.Received -= Received;
|
||||
SerialSession.Connecting -= Connecting;
|
||||
SerialSession.Connected -= Connected;
|
||||
@@ -97,7 +97,7 @@ public abstract class ReadWriteDevicesSerialSessionBase : ReadWriteDevicesBase
|
||||
try
|
||||
{
|
||||
waitingOptions ??= new WaitingOptions { ThrowBreakException = true };
|
||||
ResponsedData result = SerialSession.GetWaitingClient(waitingOptions).SendThenResponse(data, TimeOut, cancellationToken);
|
||||
ResponsedData result = SerialSession.CreateWaitingClient(waitingOptions).SendThenResponse(data, TimeOut, cancellationToken);
|
||||
return OperResult.CreateSuccessResult(result.Data);
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -112,7 +112,7 @@ public abstract class ReadWriteDevicesSerialSessionBase : ReadWriteDevicesBase
|
||||
try
|
||||
{
|
||||
waitingOptions ??= new WaitingOptions { ThrowBreakException = true };
|
||||
ResponsedData result = await SerialSession.GetWaitingClient(waitingOptions).SendThenResponseAsync(data, TimeOut, cancellationToken);
|
||||
ResponsedData result = await SerialSession.CreateWaitingClient(waitingOptions).SendThenResponseAsync(data, TimeOut, cancellationToken);
|
||||
return OperResult.CreateSuccessResult(result.Data);
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
@@ -23,7 +23,7 @@ public abstract class ReadWriteDevicesTcpClientBase : ReadWriteDevicesBase
|
||||
public ReadWriteDevicesTcpClientBase(TcpClient tcpClient)
|
||||
{
|
||||
TcpClient = tcpClient;
|
||||
WaitingClientEx = TcpClient.GetWaitingClient(new() { ThrowBreakException = true });
|
||||
WaitingClientEx = TcpClient.CreateWaitingClient(new() { ThrowBreakException = true });
|
||||
TcpClient.Connecting -= Connecting;
|
||||
TcpClient.Connected -= Connected;
|
||||
TcpClient.Disconnecting -= Disconnecting;
|
||||
@@ -87,7 +87,7 @@ public abstract class ReadWriteDevicesTcpClientBase : ReadWriteDevicesBase
|
||||
try
|
||||
{
|
||||
waitingOptions ??= new WaitingOptions { ThrowBreakException = true, };
|
||||
ResponsedData result = TcpClient.GetWaitingClient(waitingOptions).SendThenResponse(data, TimeOut, cancellationToken);
|
||||
ResponsedData result = TcpClient.CreateWaitingClient(waitingOptions).SendThenResponse(data, TimeOut, cancellationToken);
|
||||
return OperResult.CreateSuccessResult(result.Data);
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -102,7 +102,7 @@ public abstract class ReadWriteDevicesTcpClientBase : ReadWriteDevicesBase
|
||||
try
|
||||
{
|
||||
waitingOptions ??= new WaitingOptions { ThrowBreakException = true };
|
||||
ResponsedData result = await TcpClient.GetWaitingClient(waitingOptions).SendThenResponseAsync(data, TimeOut, cancellationToken);
|
||||
ResponsedData result = await TcpClient.CreateWaitingClient(waitingOptions).SendThenResponseAsync(data, TimeOut, cancellationToken);
|
||||
return OperResult.CreateSuccessResult(result.Data);
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -137,13 +137,13 @@ public abstract class ReadWriteDevicesTcpClientBase : ReadWriteDevicesBase
|
||||
|
||||
private Task Disconnected(ITcpClientBase client, DisconnectEventArgs e)
|
||||
{
|
||||
Logger?.Debug(client.IP + ":" + client.Port + "断开连接-" + e.Message);
|
||||
Logger?.Debug($"{client.IP}:{client.Port}断开连接-{e.Message}");
|
||||
return EasyTask.CompletedTask;
|
||||
}
|
||||
|
||||
private Task Disconnecting(ITcpClientBase client, DisconnectEventArgs e)
|
||||
{
|
||||
Logger?.Debug(client.IP + ":" + client.Port + "正在主动断开连接-" + e.Message);
|
||||
Logger?.Debug($"{client.IP}:{client.Port}正在主动断开连接-{e.Message}");
|
||||
return EasyTask.CompletedTask;
|
||||
}
|
||||
}
|
@@ -101,14 +101,14 @@ public abstract class ReadWriteDevicesTcpServerBase : ReadWriteDevicesBase
|
||||
/// <param name="e"></param>
|
||||
protected virtual Task Connected(SocketClient client, ConnectedEventArgs e)
|
||||
{
|
||||
Logger?.Debug(client.IP + ":" + client.Port + "连接成功");
|
||||
Logger?.Debug($"{client.IP}:{client.Port}连接成功");
|
||||
return EasyTask.CompletedTask;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected virtual Task Connecting(SocketClient client, ConnectingEventArgs e)
|
||||
{
|
||||
Logger?.Debug(client.IP + ":" + client.Port + "正在连接");
|
||||
Logger?.Debug($"{client.IP}:{client.Port}正在连接");
|
||||
SetDataAdapter(client);
|
||||
return EasyTask.CompletedTask;
|
||||
}
|
||||
@@ -116,14 +116,14 @@ public abstract class ReadWriteDevicesTcpServerBase : ReadWriteDevicesBase
|
||||
/// <inheritdoc/>
|
||||
protected virtual Task Disconnected(ITcpClientBase client, DisconnectEventArgs e)
|
||||
{
|
||||
Logger?.Debug(client.IP + ":" + client.Port + "断开连接-" + e.Message);
|
||||
Logger?.Debug($"{client.IP}:{client.Port}断开连接-{e.Message}");
|
||||
return EasyTask.CompletedTask;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected virtual Task Disconnecting(ITcpClientBase client, DisconnectEventArgs e)
|
||||
{
|
||||
Logger?.Debug(client.IP + ":" + client.Port + "正在主动断开连接-" + e.Message);
|
||||
Logger?.Debug($"{client.IP}:{client.Port}正在主动断开连接-{e.Message}");
|
||||
return EasyTask.CompletedTask;
|
||||
}
|
||||
|
||||
|
@@ -22,7 +22,7 @@ public abstract class ReadWriteDevicesUdpSessionBase : ReadWriteDevicesBase
|
||||
{
|
||||
UdpSession = udpSession;
|
||||
SetDataAdapter();
|
||||
WaitingClientEx = UdpSession.GetWaitingClient(new() { ThrowBreakException = true });
|
||||
WaitingClientEx = UdpSession.CreateWaitingClient(new() { ThrowBreakException = true });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -65,7 +65,7 @@ public abstract class ReadWriteDevicesUdpSessionBase : ReadWriteDevicesBase
|
||||
try
|
||||
{
|
||||
waitingOptions ??= new WaitingOptions { ThrowBreakException = true };
|
||||
ResponsedData result = UdpSession.GetWaitingClient(waitingOptions).SendThenResponse(data, TimeOut, cancellationToken);
|
||||
ResponsedData result = UdpSession.CreateWaitingClient(waitingOptions).SendThenResponse(data, TimeOut, cancellationToken);
|
||||
return OperResult.CreateSuccessResult(result.Data);
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -80,7 +80,7 @@ public abstract class ReadWriteDevicesUdpSessionBase : ReadWriteDevicesBase
|
||||
try
|
||||
{
|
||||
waitingOptions ??= new WaitingOptions { ThrowBreakException = true };
|
||||
ResponsedData result = await UdpSession.GetWaitingClient(waitingOptions).SendThenResponseAsync(data, TimeOut, cancellationToken);
|
||||
ResponsedData result = await UdpSession.CreateWaitingClient(waitingOptions).SendThenResponseAsync(data, TimeOut, cancellationToken);
|
||||
return OperResult.CreateSuccessResult(result.Data);
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
@@ -20,6 +20,12 @@ public sealed class EasyLock
|
||||
private static long lockWaitCount;
|
||||
private readonly SemaphoreSlim m_waiterLock = new SemaphoreSlim(1);
|
||||
/// <inheritdoc/>
|
||||
public EasyLock(bool initialState = true)
|
||||
{
|
||||
if (!initialState)
|
||||
m_waiterLock.Wait();
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
~EasyLock()
|
||||
{
|
||||
m_waiterLock.SafeDispose();
|
||||
@@ -54,11 +60,12 @@ public sealed class EasyLock
|
||||
/// <summary>
|
||||
/// 进入锁
|
||||
/// </summary>
|
||||
public void Wait(TimeSpan timeSpan, CancellationToken cancellationToken)
|
||||
public bool Wait(TimeSpan timeSpan, CancellationToken cancellationToken)
|
||||
{
|
||||
Interlocked.Increment(ref lockWaitCount);
|
||||
m_waiterLock.Wait(timeSpan, cancellationToken);
|
||||
var data = m_waiterLock.Wait(timeSpan, cancellationToken);
|
||||
Interlocked.Decrement(ref lockWaitCount);
|
||||
return data;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -73,11 +80,12 @@ public sealed class EasyLock
|
||||
/// <summary>
|
||||
/// 进入锁
|
||||
/// </summary>
|
||||
public async Task WaitAsync(TimeSpan timeSpan, CancellationToken cancellationToken)
|
||||
public async Task<bool> WaitAsync(TimeSpan timeSpan, CancellationToken cancellationToken)
|
||||
{
|
||||
Interlocked.Increment(ref lockWaitCount);
|
||||
await m_waiterLock.WaitAsync(timeSpan, cancellationToken);
|
||||
var data = await m_waiterLock.WaitAsync(timeSpan, cancellationToken);
|
||||
Interlocked.Decrement(ref lockWaitCount);
|
||||
return data;
|
||||
}
|
||||
|
||||
}
|
@@ -28,7 +28,7 @@ public class ByteTransformUtil
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new OperResult<TResult>(string.Format("{0} {1} : Length({2}) {3}", "转换失败", result.Content.ToHexString(), result.Content.Length, ex.Message));
|
||||
return new OperResult<TResult>(string.Format("{0} {1} : Length({2}) {3}", "转换失败", result.Content.ToHexString(), result.Content.Length, ex));
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -32,7 +32,7 @@ public static class JTokenUtil
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
tagValue = JToken.Parse("\"" + item + "\"");
|
||||
tagValue = JToken.Parse($"\"{item}\"");
|
||||
}
|
||||
|
||||
return tagValue;
|
||||
|
@@ -27,8 +27,7 @@ using System.Runtime.CompilerServices;
|
||||
namespace ThingsGateway.Foundation.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// 具有释放的对象。
|
||||
/// 并未实现析构函数相关。
|
||||
/// 具有释放的对象。内部实现了GC.SuppressFinalize,但不包括析构函数相关。
|
||||
/// </summary>
|
||||
public partial class DisposableObject : IDisposable
|
||||
{
|
||||
@@ -65,11 +64,12 @@ namespace ThingsGateway.Foundation.Core
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 释放资源。
|
||||
/// 释放资源。内部已经处理了<see cref="GC.SuppressFinalize(object)"/>
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
this.Dispose(disposing: true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
@@ -72,7 +72,7 @@ namespace ThingsGateway.Foundation.Core
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.OnError(ex.Message, false, true);
|
||||
this.OnError(ex.ToString(), false, true);
|
||||
}
|
||||
}
|
||||
return FilterResult.GoOn;
|
||||
@@ -121,7 +121,7 @@ namespace ThingsGateway.Foundation.Core
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.OnError(ex.Message, false, true);
|
||||
this.OnError(ex.ToString(), false, true);
|
||||
}
|
||||
}
|
||||
return FilterResult.GoOn;
|
||||
|
@@ -87,7 +87,7 @@ namespace ThingsGateway.Foundation.Core
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.OnError(ex.Message);
|
||||
this.OnError(ex.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -182,7 +182,7 @@ namespace ThingsGateway.Foundation.Core
|
||||
}
|
||||
if (!flag && !converter.CanConvertTo(destinationType))
|
||||
{
|
||||
throw new InvalidOperationException("无法转换成类型:" + value.ToString() + "==>" + destinationType);
|
||||
throw new InvalidOperationException($"无法转换成类型:{value.ToString()}==>{destinationType}");
|
||||
}
|
||||
try
|
||||
{
|
||||
@@ -190,7 +190,7 @@ namespace ThingsGateway.Foundation.Core
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new InvalidOperationException(" 类型转换出错:" + value.ToString() + "==>" + destinationType, e);
|
||||
throw new InvalidOperationException($" 类型转换出错:{value.ToString()}==>{destinationType}", e);
|
||||
}
|
||||
return returnValue;
|
||||
}
|
||||
|
@@ -70,6 +70,15 @@ namespace ThingsGateway.Foundation.Core
|
||||
return isPeriod;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 累计增加一个计数
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool Increment()
|
||||
{
|
||||
return this.Increment(1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 重置<see cref="Count"/>和<see cref="LastIncrement"/>
|
||||
/// </summary>
|
||||
|
@@ -47,14 +47,7 @@ namespace ThingsGateway.Foundation.Core
|
||||
/// </summary>
|
||||
public TimeSpan Period { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 重置<see cref="Count"/>和<see cref="LastIncrement"/>
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
this.m_count = 0;
|
||||
this.m_lastIncrement = default;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 累计增加计数
|
||||
@@ -78,5 +71,26 @@ namespace ThingsGateway.Foundation.Core
|
||||
Interlocked.Add(ref this.m_count, value);
|
||||
return isPeriod;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 累计增加一个计数
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool Increment()
|
||||
{
|
||||
return this.Increment(1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 重置<see cref="Count"/>和<see cref="LastIncrement"/>
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
this.m_count = 0;
|
||||
this.m_lastIncrement = default;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -133,7 +133,7 @@ namespace ThingsGateway.Foundation.Core
|
||||
catch (Exception ex)
|
||||
{
|
||||
fileStorage = null;
|
||||
msg = ex.Message;
|
||||
msg = ex.ToString();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@@ -134,7 +134,7 @@ namespace ThingsGateway.Foundation.Core
|
||||
string path = null;
|
||||
while (true)
|
||||
{
|
||||
path = Path.Combine(dir, $"{count:0000}" + ".log");
|
||||
path = Path.Combine(dir, $"{count:0000}.log");
|
||||
if (!File.Exists(path))
|
||||
{
|
||||
this.m_writer = FilePool.GetWriter(path);
|
||||
|
@@ -292,7 +292,13 @@ public static class LoggerExtensions
|
||||
{
|
||||
logger.Log(ThingsGateway.Foundation.Core.LogLevel.Error, null, msg, ex);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 输出错误日志
|
||||
/// </summary>
|
||||
public static void LogError(this ILog logger, Exception ex)
|
||||
{
|
||||
logger.Log(ThingsGateway.Foundation.Core.LogLevel.Error, null, ex.Message, ex);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 输出警示日志
|
||||
@@ -301,7 +307,13 @@ public static class LoggerExtensions
|
||||
{
|
||||
logger.Log(ThingsGateway.Foundation.Core.LogLevel.Warning, null, msg, ex);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 输出警示日志
|
||||
/// </summary>
|
||||
public static void LogWarning(this ILog logger, Exception ex)
|
||||
{
|
||||
logger.Log(ThingsGateway.Foundation.Core.LogLevel.Warning, null, ex.Message, ex);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 输出警示日志
|
||||
|
@@ -50,13 +50,16 @@ namespace ThingsGateway.Foundation.Dmtp
|
||||
|
||||
#region 字段
|
||||
|
||||
private ClientWebSocket m_client;
|
||||
private Func<string, IDmtpActor> m_findDmtpActor;
|
||||
private ValueCounter m_receiveCounter;
|
||||
private ValueCounter m_sendCounter;
|
||||
private SealedDmtpActor m_dmtpActor;
|
||||
private TcpDmtpAdapter m_smtpAdapter;
|
||||
private readonly SemaphoreSlim m_semaphore = new SemaphoreSlim(1, 1);
|
||||
private ClientWebSocket m_client;
|
||||
private SealedDmtpActor m_dmtpActor;
|
||||
private Func<string, IDmtpActor> m_findDmtpActor;
|
||||
private int m_receiveBufferSize = 1024 * 10;
|
||||
private ValueCounter m_receiveCounter;
|
||||
private int m_sendBufferSize = 1024 * 10;
|
||||
private ValueCounter m_sendCounter;
|
||||
private TcpDmtpAdapter m_smtpAdapter;
|
||||
|
||||
#endregion 字段
|
||||
|
||||
/// <inheritdoc/>
|
||||
@@ -90,25 +93,21 @@ namespace ThingsGateway.Foundation.Dmtp
|
||||
/// <inheritdoc/>
|
||||
public DateTime LastSendTime => this.m_sendCounter.LastIncrement;
|
||||
|
||||
/// <summary>
|
||||
/// 未实现
|
||||
/// </summary>
|
||||
public Func<ByteBlock, bool> OnHandleRawBuffer { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
|
||||
/// <summary>
|
||||
/// 未实现
|
||||
/// </summary>
|
||||
public Func<ByteBlock, IRequestInfo, bool> OnHandleReceivedData { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IPluginsManager PluginsManager { get; private set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Protocol Protocol { get; set; } = DmtpUtility.DmtpProtocol;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int ReceiveBufferSize => this.m_receiveBufferSize;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IPHost RemoteIPHost { get; private set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int SendBufferSize => this.m_sendBufferSize;
|
||||
|
||||
/// <summary>
|
||||
/// 发送<see cref="IDmtpActor"/>关闭消息。
|
||||
/// </summary>
|
||||
@@ -388,12 +387,12 @@ namespace ThingsGateway.Foundation.Dmtp
|
||||
|
||||
private void OnReceivePeriod(long value)
|
||||
{
|
||||
this.ReceiveBufferSize = TouchSocketUtility.HitBufferLength(value);
|
||||
this.m_receiveBufferSize = TouchSocketUtility.HitBufferLength(value);
|
||||
}
|
||||
|
||||
private void OnSendPeriod(long value)
|
||||
{
|
||||
this.SendBufferSize = TouchSocketUtility.HitBufferLength(value);
|
||||
this.m_sendBufferSize = TouchSocketUtility.HitBufferLength(value);
|
||||
}
|
||||
|
||||
private void PrivateClose(string msg)
|
||||
@@ -473,8 +472,7 @@ namespace ThingsGateway.Foundation.Dmtp
|
||||
{
|
||||
task = this.m_client.SendAsync(transferBytes[i], WebSocketMessageType.Binary, false, CancellationToken.None);
|
||||
}
|
||||
task.ConfigureAwait(false);
|
||||
task.GetAwaiter().GetResult();
|
||||
task.GetFalseAwaitResult();
|
||||
this.m_sendCounter.Increment(transferBytes[i].Count);
|
||||
}
|
||||
}
|
||||
@@ -522,9 +520,8 @@ namespace ThingsGateway.Foundation.Dmtp
|
||||
/// <summary>
|
||||
/// 不支持该功能
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="NotSupportedException"></exception>
|
||||
public IReceiver CreateReceiver()
|
||||
public void ClearReceiver()
|
||||
{
|
||||
throw new NotSupportedException("不支持该功能");
|
||||
}
|
||||
@@ -532,12 +529,13 @@ namespace ThingsGateway.Foundation.Dmtp
|
||||
/// <summary>
|
||||
/// 不支持该功能
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="NotSupportedException"></exception>
|
||||
public void ClearReceiver()
|
||||
public IReceiver CreateReceiver()
|
||||
{
|
||||
throw new NotSupportedException("不支持该功能");
|
||||
}
|
||||
|
||||
#endregion
|
||||
#endregion Receiver
|
||||
}
|
||||
}
|
@@ -374,7 +374,7 @@ namespace ThingsGateway.Foundation.Http
|
||||
/// <returns></returns>
|
||||
public static TResponse SetContentTypeFromFileName<TResponse>(this TResponse response, string fileName) where TResponse : HttpResponse
|
||||
{
|
||||
var contentDisposition = "attachment;" + "filename=" + System.Web.HttpUtility.UrlEncode(fileName);
|
||||
var contentDisposition = $"attachment;filename={System.Web.HttpUtility.UrlEncode(fileName)}";
|
||||
response.Headers.Add(HttpHeaders.ContentDisposition, contentDisposition);
|
||||
return response;
|
||||
}
|
||||
@@ -429,7 +429,7 @@ namespace ThingsGateway.Foundation.Http
|
||||
using (var reader = FilePool.GetReader(filePath))
|
||||
{
|
||||
response.SetContentTypeByExtension(Path.GetExtension(filePath));
|
||||
var contentDisposition = "attachment;" + "filename=" + System.Web.HttpUtility.UrlEncode(fileName ?? Path.GetFileName(filePath));
|
||||
var contentDisposition = $"attachment;filename={System.Web.HttpUtility.UrlEncode(fileName ?? Path.GetFileName(filePath))}";
|
||||
response.Headers.Add(HttpHeaders.ContentDisposition, contentDisposition);
|
||||
response.Headers.Add(HttpHeaders.AcceptRanges, "bytes");
|
||||
|
||||
@@ -526,7 +526,7 @@ namespace ThingsGateway.Foundation.Http
|
||||
using (var reader = FilePool.GetReader(filePath))
|
||||
{
|
||||
context.Response.SetContentTypeByExtension(Path.GetExtension(filePath));
|
||||
var contentDisposition = "attachment;" + "filename=" + System.Web.HttpUtility.UrlEncode(fileName ?? Path.GetFileName(filePath));
|
||||
var contentDisposition = $"attachment;filename={System.Web.HttpUtility.UrlEncode(fileName ?? Path.GetFileName(filePath))}";
|
||||
context.Response.Headers.Add(HttpHeaders.ContentDisposition, contentDisposition);
|
||||
context.Response.Headers.Add(HttpHeaders.AcceptRanges, "bytes");
|
||||
|
||||
|
@@ -66,7 +66,7 @@ namespace ThingsGateway.Foundation.Http.WebSockets
|
||||
args.Context.Response.Build(byteBlock);
|
||||
await client.DefaultSendAsync(byteBlock).ConfigureAwait(false);
|
||||
}
|
||||
await client.PluginsManager.RaiseAsync(nameof(IWebSocketHandshakedPlugin.OnWebSocketHandshaked), client, new HttpContextEventArgs(httpContext))
|
||||
_ = client.PluginsManager.RaiseAsync(nameof(IWebSocketHandshakedPlugin.OnWebSocketHandshaked), client, new HttpContextEventArgs(httpContext))
|
||||
.ConfigureAwait(false);
|
||||
return true;
|
||||
}
|
||||
|
@@ -101,7 +101,7 @@ namespace ThingsGateway.Foundation.Http.WebSockets
|
||||
if (await this.VerifyConnection.Invoke(client, e.Context))
|
||||
{
|
||||
e.Handled = true;
|
||||
_ = client.SwitchProtocolToWebSocket(e.Context);
|
||||
await client.SwitchProtocolToWebSocket(e.Context);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@@ -130,7 +130,7 @@ namespace ThingsGateway.Foundation.Rpc
|
||||
catch (TargetInvocationException ex)
|
||||
{
|
||||
invokeResult.Status = InvokeStatus.InvocationException;
|
||||
invokeResult.Message = ex.InnerException != null ? "函数内部发生异常,信息:" + ex.InnerException.Message : "函数内部发生异常,信息:未知";
|
||||
invokeResult.Message = ex.InnerException != null ? $"函数内部发生异常,信息:{ex.InnerException.Message}" : "函数内部发生异常,信息:未知";
|
||||
if (callContext.MethodInstance.Filters != null)
|
||||
{
|
||||
for (var i = 0; i < callContext.MethodInstance.Filters.Length; i++)
|
||||
@@ -223,7 +223,7 @@ namespace ThingsGateway.Foundation.Rpc
|
||||
catch (TargetInvocationException ex)
|
||||
{
|
||||
invokeResult.Status = InvokeStatus.InvocationException;
|
||||
invokeResult.Message = ex.InnerException != null ? "函数内部发生异常,信息:" + ex.InnerException.Message : "函数内部发生异常,信息:未知";
|
||||
invokeResult.Message = ex.InnerException != null ? $"函数内部发生异常,信息:{ex.InnerException.Message}" : "函数内部发生异常,信息:未知";
|
||||
if (callContext.MethodInstance.Filters != null)
|
||||
{
|
||||
for (var i = 0; i < callContext.MethodInstance.Filters.Length; i++)
|
||||
|
@@ -21,22 +21,12 @@ public abstract class BaseSerial : DependencyObject, ISerial
|
||||
/// 同步根。
|
||||
/// </summary>
|
||||
protected readonly object SyncRoot = new object();
|
||||
private int m_receiveBufferSize = 1024 * 10;
|
||||
private int m_sendBufferSize = 1024 * 10;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual int SendBufferSize
|
||||
{
|
||||
get => this.m_sendBufferSize;
|
||||
set => this.m_sendBufferSize = value < 1024 ? 1024 : value;
|
||||
}
|
||||
public abstract int SendBufferSize { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual int ReceiveBufferSize
|
||||
{
|
||||
get => this.m_receiveBufferSize;
|
||||
set => this.m_receiveBufferSize = value < 1024 ? 1024 : value;
|
||||
}
|
||||
public abstract int ReceiveBufferSize { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ILog Logger { get; set; }
|
@@ -24,9 +24,14 @@ internal sealed class InternalSerialCore : SerialCore
|
||||
public class SerialCore : IDisposable, ISender
|
||||
{
|
||||
/// <summary>
|
||||
/// 初始缓存大小
|
||||
/// 最小缓存尺寸
|
||||
/// </summary>
|
||||
public const int BufferSize = 1024 * 10;
|
||||
public int MinBufferSize { get; set; } = 1024 * 10;
|
||||
|
||||
/// <summary>
|
||||
/// 最大缓存尺寸
|
||||
/// </summary>
|
||||
public int MaxBufferSize { get; set; } = 1024 * 1024 * 10;
|
||||
#region 字段
|
||||
|
||||
/// <summary>
|
||||
@@ -35,14 +40,15 @@ public class SerialCore : IDisposable, ISender
|
||||
public readonly object SyncRoot = new object();
|
||||
|
||||
private long m_bufferRate;
|
||||
private bool m_disposedValue;
|
||||
private SpinLock m_lock;
|
||||
private bool m_online => MainSerialPort?.IsOpen == true;
|
||||
private int m_receiveBufferSize = BufferSize;
|
||||
private bool m_online => m_serialPort?.IsOpen == true;
|
||||
private int m_receiveBufferSize = 1024 * 10;
|
||||
private ValueCounter m_receiveCounter;
|
||||
private int m_sendBufferSize = BufferSize;
|
||||
private int m_sendBufferSize = 1024 * 10;
|
||||
private ValueCounter m_sendCounter;
|
||||
private readonly SemaphoreSlim m_semaphore = new SemaphoreSlim(1, 1);
|
||||
private readonly EasyLock m_semaphore = new EasyLock();
|
||||
private SerialPort m_serialPort;
|
||||
|
||||
#endregion 字段
|
||||
|
||||
/// <summary>
|
||||
@@ -69,7 +75,7 @@ public class SerialCore : IDisposable, ISender
|
||||
/// </summary>
|
||||
~SerialCore()
|
||||
{
|
||||
this.Dispose(disposing: false);
|
||||
this.SafeDispose();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
@@ -100,19 +106,11 @@ public class SerialCore : IDisposable, ISender
|
||||
public Action<SerialCore, ByteBlock> OnReceived { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 接收缓存池(可以设定初始值,运行时的值会根据流速自动调整)
|
||||
/// 接收缓存池,运行时的值会根据流速自动调整
|
||||
/// </summary>
|
||||
public int ReceiveBufferSize
|
||||
{
|
||||
get => this.m_receiveBufferSize;
|
||||
set
|
||||
{
|
||||
this.m_receiveBufferSize = value;
|
||||
if (this.MainSerialPort != null && !MainSerialPort.IsOpen)
|
||||
{
|
||||
this.MainSerialPort.ReadBufferSize = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -121,19 +119,11 @@ public class SerialCore : IDisposable, ISender
|
||||
public ValueCounter ReceiveCounter { get => this.m_receiveCounter; }
|
||||
|
||||
/// <summary>
|
||||
/// 发送缓存池(可以设定初始值,运行时的值会根据流速自动调整)
|
||||
/// 发送缓存池,运行时的值会根据流速自动调整
|
||||
/// </summary>
|
||||
public int SendBufferSize
|
||||
{
|
||||
get => this.m_sendBufferSize;
|
||||
set
|
||||
{
|
||||
this.m_sendBufferSize = value;
|
||||
if (this.MainSerialPort != null && !MainSerialPort.IsOpen)
|
||||
{
|
||||
this.MainSerialPort.WriteBufferSize = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -144,7 +134,7 @@ public class SerialCore : IDisposable, ISender
|
||||
/// <summary>
|
||||
/// SerialPort
|
||||
/// </summary>
|
||||
public SerialPort MainSerialPort { get; private set; }
|
||||
public SerialPort MainSerialPort { get => this.m_serialPort; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
@@ -155,11 +145,12 @@ public class SerialCore : IDisposable, ISender
|
||||
var byteBlock = BytePool.Default.GetByteBlock(this.ReceiveBufferSize);
|
||||
this.UserToken = byteBlock;
|
||||
byteBlock.SetLength(0);
|
||||
if (this.MainSerialPort.BytesToRead > 0)
|
||||
if (this.m_serialPort.BytesToRead > 0)
|
||||
{
|
||||
this.m_bufferRate += 2;
|
||||
this.ProcessReceived();
|
||||
}
|
||||
MainSerialPort.DataReceived += MainSerialPort_DataReceived;
|
||||
m_serialPort.DataReceived += MainSerialPort_DataReceived;
|
||||
}
|
||||
|
||||
private void MainSerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
|
||||
@@ -171,7 +162,7 @@ public class SerialCore : IDisposable, ISender
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.PrivateBreakOut(false, ex.Message);
|
||||
this.PrivateBreakOut(false, ex.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -189,12 +180,12 @@ public class SerialCore : IDisposable, ISender
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
this.Dispose(disposing: true);
|
||||
GC.SuppressFinalize(this);
|
||||
UserToken.SafeDispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 重置环境,并设置新的<see cref="MainSerialPort"/>。
|
||||
/// 重置环境,并设置新的<see cref="m_serialPort"/>。
|
||||
/// </summary>
|
||||
/// <param name="socket"></param>
|
||||
public virtual void Reset(SerialPort socket)
|
||||
@@ -209,7 +200,7 @@ public class SerialCore : IDisposable, ISender
|
||||
throw new Exception("新的SerialPort必须在连接状态。");
|
||||
}
|
||||
this.Reset();
|
||||
this.MainSerialPort = socket;
|
||||
this.m_serialPort = socket;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -219,14 +210,14 @@ public class SerialCore : IDisposable, ISender
|
||||
{
|
||||
this.m_receiveCounter.Reset();
|
||||
this.m_sendCounter.Reset();
|
||||
this.MainSerialPort = null;
|
||||
this.m_serialPort = null;
|
||||
this.OnReceived = null;
|
||||
this.OnBreakOut = null;
|
||||
this.UserToken = null;
|
||||
this.m_bufferRate = 1;
|
||||
this.m_lock = new SpinLock();
|
||||
this.m_receiveBufferSize = BufferSize;
|
||||
this.m_sendBufferSize = BufferSize;
|
||||
this.m_receiveBufferSize = this.MinBufferSize;
|
||||
this.m_sendBufferSize = this.MinBufferSize;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -244,7 +235,7 @@ public class SerialCore : IDisposable, ISender
|
||||
try
|
||||
{
|
||||
this.m_lock.Enter(ref lockTaken);
|
||||
this.MainSerialPort.Write(buffer, offset, length);
|
||||
this.m_serialPort.Write(buffer, offset, length);
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -267,7 +258,7 @@ public class SerialCore : IDisposable, ISender
|
||||
{
|
||||
await this.m_semaphore.WaitAsync();
|
||||
|
||||
this.MainSerialPort.Write(buffer, offset, length);
|
||||
this.m_serialPort.Write(buffer, offset, length);
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -287,22 +278,7 @@ public class SerialCore : IDisposable, ISender
|
||||
this.OnBreakOut?.Invoke(this, manual, msg);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 释放对象
|
||||
/// </summary>
|
||||
/// <param name="disposing"></param>
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!this.m_disposedValue)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
}
|
||||
|
||||
this.m_disposedValue = true;
|
||||
}
|
||||
UserToken.SafeDispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当发生异常的时候
|
||||
@@ -341,12 +317,20 @@ public class SerialCore : IDisposable, ISender
|
||||
|
||||
private void OnReceivePeriod(long value)
|
||||
{
|
||||
this.ReceiveBufferSize = TouchSocketUtility.HitBufferLength(value);
|
||||
this.m_receiveBufferSize = Math.Max(TouchSocketUtility.HitBufferLength(value), this.MinBufferSize);
|
||||
if (this.MainSerialPort != null && !MainSerialPort.IsOpen)
|
||||
{
|
||||
this.MainSerialPort.ReadBufferSize = this.m_receiveBufferSize;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnSendPeriod(long value)
|
||||
{
|
||||
this.SendBufferSize = TouchSocketUtility.HitBufferLength(value);
|
||||
this.m_sendBufferSize = Math.Max(TouchSocketUtility.HitBufferLength(value), this.MinBufferSize);
|
||||
if (this.MainSerialPort != null && !MainSerialPort.IsOpen)
|
||||
{
|
||||
this.MainSerialPort.WriteBufferSize = this.m_sendBufferSize;
|
||||
}
|
||||
}
|
||||
|
||||
private void PrivateBreakOut(bool manual, string msg)
|
||||
@@ -367,21 +351,21 @@ public class SerialCore : IDisposable, ISender
|
||||
UserToken?.SafeDispose();
|
||||
return;
|
||||
}
|
||||
if (MainSerialPort.BytesToRead > 0)
|
||||
if (m_serialPort.BytesToRead > 0)
|
||||
{
|
||||
var byteBlock = UserToken;
|
||||
byte[] buffer = BytePool.Default.Rent(MainSerialPort.BytesToRead);
|
||||
int num = MainSerialPort.Read(buffer, 0, MainSerialPort.BytesToRead);
|
||||
byte[] buffer = BytePool.Default.Rent(m_serialPort.BytesToRead);
|
||||
int num = m_serialPort.Read(buffer, 0, m_serialPort.BytesToRead);
|
||||
byteBlock.Write(buffer, 0, num);
|
||||
byteBlock.SetLength(num);
|
||||
this.HandleBuffer(byteBlock);
|
||||
try
|
||||
{
|
||||
var newByteBlock = BytePool.Default.GetByteBlock((int)Math.Min(this.ReceiveBufferSize * this.m_bufferRate, TouchSocketUtility.MaxBufferLength));
|
||||
var newByteBlock = BytePool.Default.GetByteBlock((int)Math.Min(this.ReceiveBufferSize * this.m_bufferRate, this.MaxBufferSize));
|
||||
newByteBlock.SetLength(0);
|
||||
UserToken = newByteBlock;
|
||||
|
||||
if (MainSerialPort.BytesToRead > 0)
|
||||
if (m_serialPort.BytesToRead > 0)
|
||||
{
|
||||
this.m_bufferRate += 2;
|
||||
this.ProcessReceived();
|
||||
@@ -389,7 +373,7 @@ public class SerialCore : IDisposable, ISender
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.PrivateBreakOut(false, ex.Message);
|
||||
this.PrivateBreakOut(false, ex.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -57,7 +57,7 @@ public class SerialSessionBase : BaseSerial, ISerialSession
|
||||
|
||||
private DelaySender m_delaySender;
|
||||
private bool m_online => MainSerialPort?.IsOpen == true;
|
||||
private readonly SemaphoreSlim m_semaphore = new SemaphoreSlim(1, 1);
|
||||
private readonly EasyLock m_semaphore = new();
|
||||
private readonly InternalSerialCore m_serialCore;
|
||||
#endregion 变量
|
||||
|
||||
@@ -204,10 +204,10 @@ public class SerialSessionBase : BaseSerial, ISerialSession
|
||||
#region 属性
|
||||
|
||||
/// <inheritdoc/>
|
||||
public DateTime LastReceivedTime => this.GetTcpCore().ReceiveCounter.LastIncrement;
|
||||
public DateTime LastReceivedTime => this.GetSerialCore().ReceiveCounter.LastIncrement;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public DateTime LastSendTime => this.GetTcpCore().SendCounter.LastIncrement;
|
||||
public DateTime LastSendTime => this.GetSerialCore().SendCounter.LastIncrement;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IContainer Container { get; private set; }
|
||||
@@ -321,7 +321,7 @@ public class SerialSessionBase : BaseSerial, ISerialSession
|
||||
|
||||
private void BeginReceive()
|
||||
{
|
||||
this.GetTcpCore().BeginIocpReceive();
|
||||
this.GetSerialCore().BeginIocpReceive();
|
||||
}
|
||||
|
||||
|
||||
@@ -375,32 +375,22 @@ public class SerialSessionBase : BaseSerial, ISerialSession
|
||||
}
|
||||
}
|
||||
|
||||
private SerialCore GetTcpCore()
|
||||
private SerialCore GetSerialCore()
|
||||
{
|
||||
this.ThrowIfDisposed();
|
||||
return this.m_serialCore ?? throw new ObjectDisposedException(this.GetType().Name);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int ReceiveBufferSize
|
||||
{
|
||||
get => this.GetTcpCore().ReceiveBufferSize;
|
||||
set
|
||||
{
|
||||
this.GetTcpCore().ReceiveBufferSize = value;
|
||||
}
|
||||
get => this.GetSerialCore().ReceiveBufferSize;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int SendBufferSize
|
||||
{
|
||||
get => this.GetTcpCore().SendBufferSize;
|
||||
set
|
||||
{
|
||||
this.GetTcpCore().SendBufferSize = value;
|
||||
}
|
||||
get => this.GetSerialCore().SendBufferSize;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
@@ -728,7 +718,7 @@ public class SerialSessionBase : BaseSerial, ISerialSession
|
||||
{
|
||||
if (this.SendingData(buffer, offset, length).GetFalseAwaitResult())
|
||||
{
|
||||
this.GetTcpCore().Send(buffer, offset, length);
|
||||
this.GetSerialCore().Send(buffer, offset, length);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -737,7 +727,7 @@ public class SerialSessionBase : BaseSerial, ISerialSession
|
||||
{
|
||||
if (await this.SendingData(buffer, offset, length))
|
||||
{
|
||||
await this.GetTcpCore().SendAsync(buffer, offset, length);
|
||||
await this.GetSerialCore().SendAsync(buffer, offset, length);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -770,7 +760,15 @@ public class SerialSessionBase : BaseSerial, ISerialSession
|
||||
this.m_serialCore.Reset(serialPort);
|
||||
this.m_serialCore.OnReceived = this.HandleReceived;
|
||||
this.m_serialCore.OnBreakOut = this.BreakOut;
|
||||
if (this.Config.GetValue(TouchSocketConfigExtension.MinBufferSizeProperty) is int minValue)
|
||||
{
|
||||
this.m_serialCore.MinBufferSize = minValue;
|
||||
}
|
||||
|
||||
if (this.Config.GetValue(TouchSocketConfigExtension.MaxBufferSizeProperty) is int maxValue)
|
||||
{
|
||||
this.m_serialCore.MaxBufferSize = maxValue;
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleReceived(SerialCore core, ByteBlock byteBlock)
|
||||
|
@@ -35,22 +35,11 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
/// </summary>
|
||||
protected readonly object SyncRoot = new object();
|
||||
|
||||
private int m_receiveBufferSize = 1024 * 10;
|
||||
private int m_sendBufferSize = 1024 * 10;
|
||||
/// <inheritdoc/>
|
||||
public abstract int SendBufferSize { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual int SendBufferSize
|
||||
{
|
||||
get => this.m_sendBufferSize;
|
||||
set => this.m_sendBufferSize = value < 1024 ? 1024 : value;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual int ReceiveBufferSize
|
||||
{
|
||||
get => this.m_receiveBufferSize;
|
||||
set => this.m_receiveBufferSize = value < 1024 ? 1024 : value;
|
||||
}
|
||||
public abstract int ReceiveBufferSize { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ILog Logger { get; set; }
|
||||
|
@@ -108,10 +108,6 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 最大BufferLength
|
||||
/// </summary>
|
||||
public static int MaxBufferLength { get; set; } = 1024 * 1024 * 10;
|
||||
|
||||
/// <summary>
|
||||
/// 命中BufferLength
|
||||
|
@@ -24,9 +24,15 @@ public class TcpCore : SocketAsyncEventArgs, IDisposable, ISender
|
||||
private const string m_msg1 = "远程终端主动关闭";
|
||||
|
||||
/// <summary>
|
||||
/// 初始缓存大小
|
||||
/// 最小缓存尺寸
|
||||
/// </summary>
|
||||
public const int BufferSize = 1024 * 10;
|
||||
public int MinBufferSize { get; set; } = 1024 * 10;
|
||||
|
||||
/// <summary>
|
||||
/// 最大缓存尺寸
|
||||
/// </summary>
|
||||
public int MaxBufferSize { get; set; } = 1024 * 1024 * 10;
|
||||
|
||||
#region 字段
|
||||
|
||||
/// <summary>
|
||||
@@ -35,14 +41,14 @@ public class TcpCore : SocketAsyncEventArgs, IDisposable, ISender
|
||||
public readonly object SyncRoot = new object();
|
||||
|
||||
private long m_bufferRate;
|
||||
private bool m_disposedValue;
|
||||
private SpinLock m_lock;
|
||||
private volatile bool m_online;
|
||||
private int m_receiveBufferSize = BufferSize;
|
||||
private int m_receiveBufferSize = 1024 * 10;
|
||||
private ValueCounter m_receiveCounter;
|
||||
private int m_sendBufferSize = BufferSize;
|
||||
private int m_sendBufferSize = 1024 * 10;
|
||||
private ValueCounter m_sendCounter;
|
||||
private readonly SemaphoreSlim m_semaphore = new SemaphoreSlim(1, 1);
|
||||
private Socket m_socket;
|
||||
private readonly EasyLock m_semaphore = new();
|
||||
#endregion 字段
|
||||
|
||||
/// <summary>
|
||||
@@ -64,14 +70,6 @@ public class TcpCore : SocketAsyncEventArgs, IDisposable, ISender
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 析构函数
|
||||
/// </summary>
|
||||
~TcpCore()
|
||||
{
|
||||
this.Dispose(disposing: false);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool CanSend => this.m_online;
|
||||
|
||||
@@ -96,16 +94,11 @@ public class TcpCore : SocketAsyncEventArgs, IDisposable, ISender
|
||||
public Action<TcpCore, ByteBlock> OnReceived { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 接收缓存池(可以设定初始值,运行时的值会根据流速自动调整)
|
||||
/// 接收缓存池,运行时的值会根据流速自动调整
|
||||
/// </summary>
|
||||
public int ReceiveBufferSize
|
||||
{
|
||||
get => this.m_receiveBufferSize;
|
||||
set
|
||||
{
|
||||
this.m_receiveBufferSize = value;
|
||||
this.Socket.ReceiveBufferSize = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -114,16 +107,11 @@ public class TcpCore : SocketAsyncEventArgs, IDisposable, ISender
|
||||
public ValueCounter ReceiveCounter { get => this.m_receiveCounter; }
|
||||
|
||||
/// <summary>
|
||||
/// 发送缓存池(可以设定初始值,运行时的值会根据流速自动调整)
|
||||
/// 发送缓存池,运行时的值会根据流速自动调整
|
||||
/// </summary>
|
||||
public int SendBufferSize
|
||||
{
|
||||
get => this.m_sendBufferSize;
|
||||
set
|
||||
{
|
||||
this.m_sendBufferSize = value;
|
||||
this.Socket.SendBufferSize = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -134,7 +122,7 @@ public class TcpCore : SocketAsyncEventArgs, IDisposable, ISender
|
||||
/// <summary>
|
||||
/// Socket
|
||||
/// </summary>
|
||||
public Socket Socket { get; private set; }
|
||||
public Socket Socket { get => this.m_socket; }
|
||||
|
||||
/// <summary>
|
||||
/// 提供一个用于客户端-服务器通信的流,该流使用安全套接字层 (SSL) 安全协议对服务器和(可选)客户端进行身份验证。
|
||||
@@ -152,7 +140,7 @@ public class TcpCore : SocketAsyncEventArgs, IDisposable, ISender
|
||||
/// <param name="sslOption"></param>
|
||||
public virtual void Authenticate(ServiceSslOption sslOption)
|
||||
{
|
||||
var sslStream = (sslOption.CertificateValidationCallback != null) ? new SslStream(new NetworkStream(this.Socket, false), false, sslOption.CertificateValidationCallback) : new SslStream(new NetworkStream(this.Socket, false), false);
|
||||
var sslStream = (sslOption.CertificateValidationCallback != null) ? new SslStream(new NetworkStream(this.m_socket, false), false, sslOption.CertificateValidationCallback) : new SslStream(new NetworkStream(this.m_socket, false), false);
|
||||
sslStream.AuthenticateAsServer(sslOption.Certificate);
|
||||
|
||||
this.SslStream = sslStream;
|
||||
@@ -165,7 +153,7 @@ public class TcpCore : SocketAsyncEventArgs, IDisposable, ISender
|
||||
/// <param name="sslOption"></param>
|
||||
public virtual void Authenticate(ClientSslOption sslOption)
|
||||
{
|
||||
var sslStream = (sslOption.CertificateValidationCallback != null) ? new SslStream(new NetworkStream(this.Socket, false), false, sslOption.CertificateValidationCallback) : new SslStream(new NetworkStream(this.Socket, false), false);
|
||||
var sslStream = (sslOption.CertificateValidationCallback != null) ? new SslStream(new NetworkStream(this.m_socket, false), false, sslOption.CertificateValidationCallback) : new SslStream(new NetworkStream(this.m_socket, false), false);
|
||||
if (sslOption.ClientCertificates == null)
|
||||
{
|
||||
sslStream.AuthenticateAsClient(sslOption.TargetHost);
|
||||
@@ -185,7 +173,7 @@ public class TcpCore : SocketAsyncEventArgs, IDisposable, ISender
|
||||
/// <returns></returns>
|
||||
public virtual async Task AuthenticateAsync(ServiceSslOption sslOption)
|
||||
{
|
||||
var sslStream = (sslOption.CertificateValidationCallback != null) ? new SslStream(new NetworkStream(this.Socket, false), false, sslOption.CertificateValidationCallback) : new SslStream(new NetworkStream(this.Socket, false), false);
|
||||
var sslStream = (sslOption.CertificateValidationCallback != null) ? new SslStream(new NetworkStream(this.m_socket, false), false, sslOption.CertificateValidationCallback) : new SslStream(new NetworkStream(this.m_socket, false), false);
|
||||
await sslStream.AuthenticateAsServerAsync(sslOption.Certificate);
|
||||
|
||||
this.SslStream = sslStream;
|
||||
@@ -199,7 +187,7 @@ public class TcpCore : SocketAsyncEventArgs, IDisposable, ISender
|
||||
/// <returns></returns>
|
||||
public virtual async Task AuthenticateAsync(ClientSslOption sslOption)
|
||||
{
|
||||
var sslStream = (sslOption.CertificateValidationCallback != null) ? new SslStream(new NetworkStream(this.Socket, false), false, sslOption.CertificateValidationCallback) : new SslStream(new NetworkStream(this.Socket, false), false);
|
||||
var sslStream = (sslOption.CertificateValidationCallback != null) ? new SslStream(new NetworkStream(this.m_socket, false), false, sslOption.CertificateValidationCallback) : new SslStream(new NetworkStream(this.m_socket, false), false);
|
||||
if (sslOption.ClientCertificates == null)
|
||||
{
|
||||
await sslStream.AuthenticateAsClientAsync(sslOption.TargetHost);
|
||||
@@ -220,8 +208,9 @@ public class TcpCore : SocketAsyncEventArgs, IDisposable, ISender
|
||||
var byteBlock = BytePool.Default.GetByteBlock(this.ReceiveBufferSize);
|
||||
this.UserToken = byteBlock;
|
||||
this.SetBuffer(byteBlock.Buffer, 0, byteBlock.Capacity);
|
||||
if (!this.Socket.ReceiveAsync(this))
|
||||
if (!this.m_socket.ReceiveAsync(this))
|
||||
{
|
||||
this.m_bufferRate += 2;
|
||||
this.ProcessReceived(this);
|
||||
}
|
||||
}
|
||||
@@ -257,7 +246,7 @@ public class TcpCore : SocketAsyncEventArgs, IDisposable, ISender
|
||||
catch (Exception ex)
|
||||
{
|
||||
byteBlock.Dispose();
|
||||
this.PrivateBreakOut(false, ex.Message);
|
||||
this.PrivateBreakOut(false, ex.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -271,15 +260,6 @@ public class TcpCore : SocketAsyncEventArgs, IDisposable, ISender
|
||||
this.PrivateBreakOut(true, msg);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 释放对象
|
||||
/// </summary>
|
||||
public new void Dispose()
|
||||
{
|
||||
// 不要更改此代码。请将清理代码放入“Dispose(bool disposing)”方法中
|
||||
this.Dispose(disposing: true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 重置环境,并设置新的<see cref="Socket"/>。
|
||||
@@ -298,7 +278,7 @@ public class TcpCore : SocketAsyncEventArgs, IDisposable, ISender
|
||||
}
|
||||
this.Reset();
|
||||
this.m_online = true;
|
||||
this.Socket = socket;
|
||||
this.m_socket = socket;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -310,14 +290,14 @@ public class TcpCore : SocketAsyncEventArgs, IDisposable, ISender
|
||||
this.m_sendCounter.Reset();
|
||||
this.SslStream?.Dispose();
|
||||
this.SslStream = null;
|
||||
this.Socket = null;
|
||||
this.m_socket = null;
|
||||
this.OnReceived = null;
|
||||
this.OnBreakOut = null;
|
||||
this.UserToken = null;
|
||||
this.m_bufferRate = 1;
|
||||
this.m_lock = new SpinLock();
|
||||
this.m_receiveBufferSize = BufferSize;
|
||||
this.m_sendBufferSize = BufferSize;
|
||||
this.m_receiveBufferSize = this.MinBufferSize;
|
||||
this.m_sendBufferSize = this.MinBufferSize;
|
||||
this.m_online = false;
|
||||
}
|
||||
|
||||
@@ -344,7 +324,7 @@ public class TcpCore : SocketAsyncEventArgs, IDisposable, ISender
|
||||
this.m_lock.Enter(ref lockTaken);
|
||||
while (length > 0)
|
||||
{
|
||||
var r = this.Socket.Send(buffer, offset, length, SocketFlags.None);
|
||||
var r = this.m_socket.Send(buffer, offset, length, SocketFlags.None);
|
||||
if (r == 0 && length > 0)
|
||||
{
|
||||
throw new Exception("发送数据不完全");
|
||||
@@ -387,7 +367,7 @@ public class TcpCore : SocketAsyncEventArgs, IDisposable, ISender
|
||||
|
||||
while (length > 0)
|
||||
{
|
||||
var r = await this.Socket.SendAsync(new ArraySegment<byte>(buffer, offset, length), SocketFlags.None, CancellationToken.None);
|
||||
var r = await this.m_socket.SendAsync(new ArraySegment<byte>(buffer, offset, length), SocketFlags.None, CancellationToken.None);
|
||||
if (r == 0 && length > 0)
|
||||
{
|
||||
throw new Exception("发送数据不完全");
|
||||
@@ -414,7 +394,7 @@ public class TcpCore : SocketAsyncEventArgs, IDisposable, ISender
|
||||
|
||||
while (length > 0)
|
||||
{
|
||||
var r = this.Socket.Send(buffer, offset, length, SocketFlags.None);
|
||||
var r = this.m_socket.Send(buffer, offset, length, SocketFlags.None);
|
||||
if (r == 0 && length > 0)
|
||||
{
|
||||
throw new Exception("发送数据不完全");
|
||||
@@ -443,23 +423,6 @@ public class TcpCore : SocketAsyncEventArgs, IDisposable, ISender
|
||||
this.OnBreakOut?.Invoke(this, manual, msg);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 释放对象
|
||||
/// </summary>
|
||||
/// <param name="disposing"></param>
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!this.m_disposedValue)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
}
|
||||
|
||||
this.m_disposedValue = true;
|
||||
}
|
||||
base.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当发生异常的时候
|
||||
/// </summary>
|
||||
@@ -481,7 +444,7 @@ public class TcpCore : SocketAsyncEventArgs, IDisposable, ISender
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.PrivateBreakOut(false, ex.Message);
|
||||
this.PrivateBreakOut(false, ex.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -514,12 +477,20 @@ public class TcpCore : SocketAsyncEventArgs, IDisposable, ISender
|
||||
|
||||
private void OnReceivePeriod(long value)
|
||||
{
|
||||
this.ReceiveBufferSize = TouchSocketUtility.HitBufferLength(value);
|
||||
this.m_receiveBufferSize = Math.Max(TouchSocketUtility.HitBufferLength(value), this.MinBufferSize);
|
||||
if (this.m_socket != null)
|
||||
{
|
||||
this.m_socket.ReceiveBufferSize = this.m_receiveBufferSize;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnSendPeriod(long value)
|
||||
{
|
||||
this.SendBufferSize = TouchSocketUtility.HitBufferLength(value);
|
||||
this.m_sendBufferSize = Math.Max(TouchSocketUtility.HitBufferLength(value), this.MinBufferSize);
|
||||
if (this.m_socket != null)
|
||||
{
|
||||
this.m_socket.SendBufferSize = this.m_sendBufferSize;
|
||||
}
|
||||
}
|
||||
|
||||
private void PrivateBreakOut(bool manual, string msg)
|
||||
@@ -548,11 +519,11 @@ public class TcpCore : SocketAsyncEventArgs, IDisposable, ISender
|
||||
this.HandleBuffer(byteBlock);
|
||||
try
|
||||
{
|
||||
var newByteBlock = BytePool.Default.GetByteBlock((int)Math.Min(this.ReceiveBufferSize * this.m_bufferRate, TouchSocketUtility.MaxBufferLength));
|
||||
var newByteBlock = BytePool.Default.GetByteBlock((int)Math.Min(this.ReceiveBufferSize * this.m_bufferRate, this.MaxBufferSize));
|
||||
e.UserToken = newByteBlock;
|
||||
e.SetBuffer(newByteBlock.Buffer, 0, newByteBlock.Capacity);
|
||||
|
||||
if (!this.Socket.ReceiveAsync(e))
|
||||
if (!this.m_socket.ReceiveAsync(e))
|
||||
{
|
||||
this.m_bufferRate += 2;
|
||||
this.ProcessReceived(e);
|
||||
@@ -560,7 +531,7 @@ public class TcpCore : SocketAsyncEventArgs, IDisposable, ISender
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.PrivateBreakOut(false, ex.Message);
|
||||
this.PrivateBreakOut(false, ex.ToString());
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@@ -149,7 +149,7 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.BreakOut(default, false, ex.Message);
|
||||
this.BreakOut(default, false, ex.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -227,6 +227,15 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
tcpCore.Reset(socket);
|
||||
tcpCore.OnReceived = this.HandleReceived;
|
||||
tcpCore.OnBreakOut = this.BreakOut;
|
||||
if (this.Config.GetValue(TouchSocketConfigExtension.MinBufferSizeProperty) is int minValue)
|
||||
{
|
||||
tcpCore.MinBufferSize = minValue;
|
||||
}
|
||||
|
||||
if (this.Config.GetValue(TouchSocketConfigExtension.MaxBufferSizeProperty) is int maxValue)
|
||||
{
|
||||
tcpCore.MaxBufferSize = maxValue;
|
||||
}
|
||||
this.m_tcpCore = tcpCore;
|
||||
}
|
||||
|
||||
@@ -398,20 +407,12 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
public override int ReceiveBufferSize
|
||||
{
|
||||
get => this.GetTcpCore().ReceiveBufferSize;
|
||||
set
|
||||
{
|
||||
this.GetTcpCore().ReceiveBufferSize = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int SendBufferSize
|
||||
{
|
||||
get => this.GetTcpCore().SendBufferSize;
|
||||
set
|
||||
{
|
||||
this.GetTcpCore().SendBufferSize = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
@@ -71,7 +71,7 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
|
||||
private DelaySender m_delaySender;
|
||||
private volatile bool m_online;
|
||||
private readonly SemaphoreSlim m_semaphore = new SemaphoreSlim(1, 1);
|
||||
private readonly EasyLock m_semaphore = new();
|
||||
private readonly InternalTcpCore m_tcpCore;
|
||||
#endregion 变量
|
||||
|
||||
@@ -334,10 +334,7 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
var iPHost = this.Config.GetValue(TouchSocketConfigExtension.RemoteIPHostProperty) ?? throw new ArgumentNullException(nameof(IPHost), "iPHost不能为空。");
|
||||
this.MainSocket.SafeDispose();
|
||||
var socket = this.CreateSocket(iPHost);
|
||||
this.PrivateOnConnecting(new ConnectingEventArgs(socket))
|
||||
.ConfigureAwait(false)
|
||||
.GetAwaiter()
|
||||
.GetResult();
|
||||
this.PrivateOnConnecting(new ConnectingEventArgs(socket)).GetFalseAwaitResult();
|
||||
if (timeout == 5000)
|
||||
{
|
||||
socket.Connect(iPHost.Host, iPHost.Port);
|
||||
@@ -500,6 +497,11 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
|
||||
#endregion
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ToString()
|
||||
{
|
||||
return this.GetIPPort();
|
||||
}
|
||||
private void BreakOut(TcpCore core, bool manual, string msg)
|
||||
{
|
||||
lock (this.SyncRoot)
|
||||
@@ -526,20 +528,12 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
public override int ReceiveBufferSize
|
||||
{
|
||||
get => this.GetTcpCore().ReceiveBufferSize;
|
||||
set
|
||||
{
|
||||
this.GetTcpCore().ReceiveBufferSize = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int SendBufferSize
|
||||
{
|
||||
get => this.GetTcpCore().SendBufferSize;
|
||||
set
|
||||
{
|
||||
this.GetTcpCore().SendBufferSize = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
@@ -942,7 +936,15 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
this.m_tcpCore.Reset(socket);
|
||||
this.m_tcpCore.OnReceived = this.HandleReceived;
|
||||
this.m_tcpCore.OnBreakOut = this.BreakOut;
|
||||
if (this.Config.GetValue(TouchSocketConfigExtension.MinBufferSizeProperty) is int minValue)
|
||||
{
|
||||
this.m_tcpCore.MinBufferSize = minValue;
|
||||
}
|
||||
|
||||
if (this.Config.GetValue(TouchSocketConfigExtension.MaxBufferSizeProperty) is int maxValue)
|
||||
{
|
||||
this.m_tcpCore.MaxBufferSize = maxValue;
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleReceived(TcpCore core, ByteBlock byteBlock)
|
||||
|
@@ -31,6 +31,12 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
/// </summary>
|
||||
public class TcpService<TClient> : TcpServiceBase, ITcpService<TClient> where TClient : SocketClient, new()
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override int SendBufferSize => 1024 * 1024 * 10;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int ReceiveBufferSize => 1024 * 1024 * 10;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
@@ -203,7 +209,7 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
/// <param name="e"></param>
|
||||
protected virtual Task OnDisconnecting(TClient socketClient, DisconnectEventArgs e)
|
||||
{
|
||||
if (this.Disconnected != null)
|
||||
if (this.Disconnecting != null)
|
||||
{
|
||||
return this.Disconnecting.Invoke(socketClient, e);
|
||||
}
|
||||
@@ -477,7 +483,7 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
{
|
||||
this.m_serverState = ServerState.Exception;
|
||||
|
||||
this.m_pluginsManager.Raise(nameof(IServerStartedPlugin.OnServerStarted), this, new ServiceStateEventArgs(this.m_serverState, ex) { Message = ex.Message });
|
||||
this.m_pluginsManager.Raise(nameof(IServerStartedPlugin.OnServerStarted), this, new ServiceStateEventArgs(this.m_serverState, ex) { Message = ex.ToString() });
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
@@ -155,6 +155,11 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
/// <param name="tcpCore"></param>
|
||||
public void ReturnTcpCore(TcpCore tcpCore)
|
||||
{
|
||||
if (this.DisposedValue)
|
||||
{
|
||||
tcpCore.SafeDispose();
|
||||
return;
|
||||
}
|
||||
this.m_tcpCores.Push(tcpCore);
|
||||
}
|
||||
|
||||
|
@@ -69,10 +69,14 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
this.Protocol = Protocol.Udp;
|
||||
var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
|
||||
this.Monitor = new UdpNetworkMonitor(null, socket);
|
||||
this.ReceiveBufferSize = 1024 * 64;
|
||||
this.SendBufferSize = 1024 * 64;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int ReceiveBufferSize => 64 * 1024;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int SendBufferSize => 64 * 1024;
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
@@ -332,7 +336,7 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.ServerState = ServerState.Exception;
|
||||
this.PluginsManager.Raise(nameof(IServerStartedPlugin.OnServerStarted), this, new ServiceStateEventArgs(this.ServerState, ex) { Message = ex.Message });
|
||||
this.PluginsManager.Raise(nameof(IServerStartedPlugin.OnServerStarted), this, new ServiceStateEventArgs(this.ServerState, ex) { Message = ex.ToString() });
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
@@ -55,7 +55,7 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.OnError(ex.Message);
|
||||
this.OnError(ex.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -173,7 +173,7 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new Result(ResultCode.Exception, ex.Message);
|
||||
return new Result(ResultCode.Exception, ex.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,7 +193,7 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new Result(ResultCode.Exception, ex.Message);
|
||||
return new Result(ResultCode.Exception, ex.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -24,7 +24,6 @@
|
||||
//------------------------------------------------------------------------------
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
|
||||
namespace ThingsGateway.Foundation.Sockets
|
||||
{
|
||||
/// <summary>
|
||||
@@ -358,5 +357,145 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
}
|
||||
|
||||
#endregion IUdpClientSender
|
||||
|
||||
#region IWaitSender
|
||||
/// <summary>
|
||||
/// 发送字节流
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="msg"></param>
|
||||
/// <param name="timeout"></param>
|
||||
/// <exception cref="NotConnectedException">客户端没有连接</exception>
|
||||
/// <exception cref="OverlengthException">发送数据超长</exception>
|
||||
/// <exception cref="Exception">其他异常</exception>
|
||||
/// <returns>返回的数据</returns>
|
||||
public static byte[] SendThenReturn(this IWaitSender client, string msg, int timeout = 5000)
|
||||
{
|
||||
using (var tokenSource = new CancellationTokenSource(timeout))
|
||||
{
|
||||
return client.SendThenReturn(Encoding.UTF8.GetBytes(msg), tokenSource.Token);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送字节流
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="buffer">数据缓存区</param>
|
||||
/// <param name="timeout"></param>
|
||||
/// <exception cref="NotConnectedException">客户端没有连接</exception>
|
||||
/// <exception cref="OverlengthException">发送数据超长</exception>
|
||||
/// <exception cref="Exception">其他异常</exception>
|
||||
/// <returns>返回的数据</returns>
|
||||
public static byte[] SendThenReturn(this IWaitSender client, byte[] buffer, int timeout = 5000)
|
||||
{
|
||||
using (var tokenSource = new CancellationTokenSource(timeout))
|
||||
{
|
||||
return client.SendThenReturn(buffer, 0, buffer.Length, tokenSource.Token);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送流中的有效数据
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="byteBlock">数据块载体</param>
|
||||
/// <param name="timeout"></param>
|
||||
/// <exception cref="NotConnectedException">客户端没有连接</exception>
|
||||
/// <exception cref="OverlengthException">发送数据超长</exception>
|
||||
/// <exception cref="Exception">其他异常</exception>
|
||||
/// <returns>返回的数据</returns>
|
||||
public static byte[] SendThenReturn(this IWaitSender client, ByteBlock byteBlock, int timeout = 5000)
|
||||
{
|
||||
using (var tokenSource = new CancellationTokenSource(timeout))
|
||||
{
|
||||
return client.SendThenReturn(byteBlock.Buffer, 0, byteBlock.Len, tokenSource.Token);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 异步发送
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="buffer">数据缓存区</param>
|
||||
/// <param name="timeout"></param>
|
||||
/// <exception cref="NotConnectedException">客户端没有连接</exception>
|
||||
/// <exception cref="OverlengthException">发送数据超长</exception>
|
||||
/// <exception cref="Exception">其他异常</exception>
|
||||
/// <returns>返回的数据</returns>
|
||||
public static Task<byte[]> SendThenReturnAsync(this IWaitSender client, byte[] buffer, int timeout = 5000)
|
||||
{
|
||||
using (var tokenSource = new CancellationTokenSource(timeout))
|
||||
{
|
||||
return client.SendThenReturnAsync(buffer, 0, buffer.Length, tokenSource.Token);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步发送
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="msg"></param>
|
||||
/// <param name="timeout"></param>
|
||||
/// <exception cref="NotConnectedException">客户端没有连接</exception>
|
||||
/// <exception cref="OverlengthException">发送数据超长</exception>
|
||||
/// <exception cref="Exception">其他异常</exception>
|
||||
/// <returns>返回的数据</returns>
|
||||
public static Task<byte[]> SendThenReturnAsync(this IWaitSender client, string msg, int timeout = 5000)
|
||||
{
|
||||
using (var tokenSource = new CancellationTokenSource(timeout))
|
||||
{
|
||||
return client.SendThenReturnAsync(Encoding.UTF8.GetBytes(msg), tokenSource.Token);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送字节流
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="buffer">数据缓存区</param>
|
||||
/// <param name="token">取消令箭</param>
|
||||
/// <exception cref="NotConnectedException">客户端没有连接</exception>
|
||||
/// <exception cref="OverlengthException">发送数据超长</exception>
|
||||
/// <exception cref="Exception">其他异常</exception>
|
||||
/// <returns>返回的数据</returns>
|
||||
public static byte[] SendThenReturn(this IWaitSender client, byte[] buffer, CancellationToken token)
|
||||
{
|
||||
return client.SendThenReturn(buffer, 0, buffer.Length, token);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送流中的有效数据
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="byteBlock">数据块载体</param>
|
||||
/// <param name="token">取消令箭</param>
|
||||
/// <exception cref="NotConnectedException">客户端没有连接</exception>
|
||||
/// <exception cref="OverlengthException">发送数据超长</exception>
|
||||
/// <exception cref="Exception">其他异常</exception>
|
||||
/// <returns>返回的数据</returns>
|
||||
public static byte[] SendThenReturn(this IWaitSender client, ByteBlock byteBlock, CancellationToken token)
|
||||
{
|
||||
return client.SendThenReturn(byteBlock.Buffer, 0, byteBlock.Len, token);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 异步发送
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="buffer">数据缓存区</param>
|
||||
/// <param name="token">取消令箭</param>
|
||||
/// <exception cref="NotConnectedException">客户端没有连接</exception>
|
||||
/// <exception cref="OverlengthException">发送数据超长</exception>
|
||||
/// <exception cref="Exception">其他异常</exception>
|
||||
/// <returns>返回的数据</returns>
|
||||
public static Task<byte[]> SendThenReturnAsync(this IWaitSender client, byte[] buffer, CancellationToken token)
|
||||
{
|
||||
return client.SendThenReturnAsync(buffer, 0, buffer.Length, token);
|
||||
}
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
@@ -51,6 +51,54 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
public static readonly DependencyProperty<Func<UdpDataHandlingAdapter>> UdpDataHandlingAdapterProperty = DependencyProperty<Func<UdpDataHandlingAdapter>>.Register("UdpDataHandlingAdapter", () => { return new NormalUdpDataHandlingAdapter(); });
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 最小缓存池尺寸
|
||||
/// 所需类型<see cref="int"/>
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty<int?> MinBufferSizeProperty = DependencyProperty<int?>.Register("MinBufferSize", default);
|
||||
|
||||
/// <summary>
|
||||
/// 最大缓存池尺寸
|
||||
/// 所需类型<see cref="int"/>
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty<int?> MaxBufferSizeProperty = DependencyProperty<int?>.Register("MinBufferSize", default);
|
||||
|
||||
/// <summary>
|
||||
/// 最小缓存容量,默认缺省。
|
||||
/// <list type="number">
|
||||
/// </list>
|
||||
/// </summary>
|
||||
/// <param name="config"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static TouchSocketConfig MinBufferSize(this TouchSocketConfig config, int value)
|
||||
{
|
||||
if (value < 1024)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(value), value, "数值不能小于1024");
|
||||
}
|
||||
config.SetValue(MinBufferSizeProperty, value);
|
||||
return config;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 最大缓存容量,默认缺省。
|
||||
/// <list type="number">
|
||||
/// </list>
|
||||
/// </summary>
|
||||
/// <param name="config"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static TouchSocketConfig MaxBufferSize(this TouchSocketConfig config, int value)
|
||||
{
|
||||
if (value < 1024)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(value), value, "数值不能小于1024");
|
||||
}
|
||||
config.SetValue(MaxBufferSizeProperty, value);
|
||||
return config;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送超时设定,单位毫秒,默认为0。意为禁用该配置。
|
||||
/// </summary>
|
||||
|
@@ -36,37 +36,14 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
/// <param name="buffer">数据缓存区</param>
|
||||
/// <param name="offset">偏移</param>
|
||||
/// <param name="length">长度</param>
|
||||
/// <param name="timeout">超时时间</param>
|
||||
/// <param name="cancellationToken">取消令箭</param>
|
||||
/// <param name="token">取消令箭</param>
|
||||
/// <exception cref="NotConnectedException">客户端没有连接</exception>
|
||||
/// <exception cref="OverlengthException">发送数据超长</exception>
|
||||
/// <exception cref="Exception">其他异常</exception>
|
||||
/// <returns>返回的数据</returns>
|
||||
byte[] SendThenReturn(byte[] buffer, int offset, int length, int timeout = 1000 * 5, CancellationToken cancellationToken = default);
|
||||
byte[] SendThenReturn(byte[] buffer, int offset, int length, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// 发送字节流
|
||||
/// </summary>
|
||||
/// <param name="buffer">数据缓存区</param>
|
||||
/// <param name="timeout">超时时间</param>
|
||||
/// <param name="cancellationToken">取消令箭</param>
|
||||
/// <exception cref="NotConnectedException">客户端没有连接</exception>
|
||||
/// <exception cref="OverlengthException">发送数据超长</exception>
|
||||
/// <exception cref="Exception">其他异常</exception>
|
||||
/// <returns>返回的数据</returns>
|
||||
byte[] SendThenReturn(byte[] buffer, int timeout = 1000 * 5, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// 发送流中的有效数据
|
||||
/// </summary>
|
||||
/// <param name="byteBlock">数据块载体</param>
|
||||
/// <param name="timeout">超时时间</param>
|
||||
/// <param name="cancellationToken">取消令箭</param>
|
||||
/// <exception cref="NotConnectedException">客户端没有连接</exception>
|
||||
/// <exception cref="OverlengthException">发送数据超长</exception>
|
||||
/// <exception cref="Exception">其他异常</exception>
|
||||
/// <returns>返回的数据</returns>
|
||||
byte[] SendThenReturn(ByteBlock byteBlock, int timeout = 1000 * 5, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// 异步发送
|
||||
@@ -74,36 +51,13 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
/// <param name="buffer">数据缓存区</param>
|
||||
/// <param name="offset">偏移</param>
|
||||
/// <param name="length">长度</param>
|
||||
/// <param name="timeout">超时时间</param>
|
||||
/// <param name="cancellationToken">取消令箭</param>
|
||||
/// <param name="token">取消令箭</param>
|
||||
/// <exception cref="NotConnectedException">客户端没有连接</exception>
|
||||
/// <exception cref="OverlengthException">发送数据超长</exception>
|
||||
/// <exception cref="Exception">其他异常</exception>
|
||||
/// <returns>返回的数据</returns>
|
||||
Task<byte[]> SendThenReturnAsync(byte[] buffer, int offset, int length, int timeout = 1000 * 5, CancellationToken cancellationToken = default);
|
||||
Task<byte[]> SendThenReturnAsync(byte[] buffer, int offset, int length, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// 异步发送
|
||||
/// </summary>
|
||||
/// <param name="buffer">数据缓存区</param>
|
||||
/// <param name="timeout">超时时间</param>
|
||||
/// <param name="cancellationToken">取消令箭</param>
|
||||
/// <exception cref="NotConnectedException">客户端没有连接</exception>
|
||||
/// <exception cref="OverlengthException">发送数据超长</exception>
|
||||
/// <exception cref="Exception">其他异常</exception>
|
||||
/// <returns>返回的数据</returns>
|
||||
Task<byte[]> SendThenReturnAsync(byte[] buffer, int timeout = 1000 * 5, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// 异步发送
|
||||
/// </summary>
|
||||
/// <param name="byteBlock">数据块载体</param>
|
||||
/// <param name="timeout">超时时间</param>
|
||||
/// <param name="cancellationToken">取消令箭</param>
|
||||
/// <exception cref="NotConnectedException">客户端没有连接</exception>
|
||||
/// <exception cref="OverlengthException">发送数据超长</exception>
|
||||
/// <exception cref="Exception">其他异常</exception>
|
||||
/// <returns>返回的数据</returns>
|
||||
Task<byte[]> SendThenReturnAsync(ByteBlock byteBlock, int timeout = 1000 * 5, CancellationToken cancellationToken = default);
|
||||
}
|
||||
}
|
@@ -33,12 +33,12 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
/// <summary>
|
||||
/// 发送缓存区大小。最小值=1024。
|
||||
/// </summary>
|
||||
int SendBufferSize { get; set; }
|
||||
int SendBufferSize { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 接收缓存区大小。最小值=1024。
|
||||
/// </summary>
|
||||
int ReceiveBufferSize { get; set; }
|
||||
int ReceiveBufferSize { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 日志记录器
|
||||
|
@@ -31,6 +31,24 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
[PluginOption(Singleton = true, NotRegister = true)]
|
||||
public sealed class ReconnectionPlugin<TClient> : PluginBase where TClient : class, ITcpClient
|
||||
{
|
||||
/// <summary>
|
||||
/// 重连插件
|
||||
/// </summary>
|
||||
public ReconnectionPlugin()
|
||||
{
|
||||
this.ActionForConnect = async (c) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
await c.ConnectAsync();
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
protected override void Loaded(IPluginsManager pluginsManager)
|
||||
{
|
||||
@@ -134,6 +152,21 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 每个周期可执行的委托。返回值为True标识客户端存活。返回False,表示失活,立即重连。返回null时,表示跳过此次检验。
|
||||
/// </summary>
|
||||
/// <param name="actionForCheck"></param>
|
||||
/// <returns></returns>
|
||||
public ReconnectionPlugin<TClient> SetActionForCheck(Func<TClient, int, bool?> actionForCheck)
|
||||
{
|
||||
this.ActionForCheck = async (c, i) =>
|
||||
{
|
||||
await EasyTask.CompletedTask;
|
||||
return actionForCheck.Invoke(c, i);
|
||||
};
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置连接动作
|
||||
/// </summary>
|
||||
@@ -145,6 +178,21 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置连接动作
|
||||
/// </summary>
|
||||
/// <param name="tryConnect"></param>
|
||||
/// <returns>无论如何,只要返回True,则结束本轮尝试</returns>
|
||||
public ReconnectionPlugin<TClient> SetConnectAction(Func<TClient, bool> tryConnect)
|
||||
{
|
||||
this.ActionForConnect = async (c) =>
|
||||
{
|
||||
await EasyTask.CompletedTask;
|
||||
return tryConnect.Invoke(c);
|
||||
};
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检验时间间隔
|
||||
/// </summary>
|
||||
|
@@ -121,7 +121,7 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
{
|
||||
if (this.ReturnException)
|
||||
{
|
||||
client.Send(ex.Message);
|
||||
client.Send(ex.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -18,11 +18,17 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
public class Receiver : DisposableObject, IReceiver
|
||||
{
|
||||
private readonly IClient m_client;
|
||||
private readonly AutoResetEvent m_resetEventForComplateRead = new AutoResetEvent(false);
|
||||
private readonly EasyLock m_resetEventForComplateRead = new EasyLock(false);
|
||||
private readonly AsyncAutoResetEvent m_resetEventForRead = new AsyncAutoResetEvent(false);
|
||||
private ByteBlock m_byteBlock;
|
||||
private IRequestInfo m_requestInfo;
|
||||
|
||||
/// <summary>
|
||||
/// Receiver
|
||||
/// </summary>
|
||||
~Receiver()
|
||||
{
|
||||
this.Dispose(false);
|
||||
}
|
||||
/// <summary>
|
||||
/// Receiver
|
||||
/// </summary>
|
||||
@@ -64,7 +70,7 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (this.m_resetEventForComplateRead.WaitOne(TimeSpan.FromSeconds(10)))
|
||||
if (this.m_resetEventForComplateRead.Wait(TimeSpan.FromSeconds(10), CancellationToken.None))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -74,9 +80,15 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
/// <inheritdoc/>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
this.m_client.ClearReceiver();
|
||||
this.m_resetEventForComplateRead.SafeDispose();
|
||||
this.m_resetEventForRead.SafeDispose();
|
||||
if (disposing)
|
||||
{
|
||||
this.m_client.ClearReceiver();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.m_resetEventForRead.SafeDispose();
|
||||
}
|
||||
|
||||
this.m_byteBlock = null;
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
@@ -85,7 +97,7 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
{
|
||||
this.m_byteBlock = default;
|
||||
this.m_requestInfo = default;
|
||||
this.m_resetEventForComplateRead.Set();
|
||||
this.m_resetEventForComplateRead.Release();
|
||||
}
|
||||
}
|
||||
}
|
@@ -46,37 +46,13 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
/// <param name="buffer">数据缓存区</param>
|
||||
/// <param name="offset">偏移</param>
|
||||
/// <param name="length">长度</param>
|
||||
/// <param name="timeout">超时时间</param>
|
||||
/// <param name="cancellationToken">取消令箭</param>
|
||||
/// <param name="token">取消令箭</param>
|
||||
/// <exception cref="NotConnectedException">客户端没有连接</exception>
|
||||
/// <exception cref="OverlengthException">发送数据超长</exception>
|
||||
/// <exception cref="Exception">其他异常</exception>
|
||||
/// <returns>返回的数据</returns>
|
||||
ResponsedData SendThenResponse(byte[] buffer, int offset, int length, int timeout = 1000 * 5, CancellationToken cancellationToken = default);
|
||||
ResponsedData SendThenResponse(byte[] buffer, int offset, int length, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// 发送字节流
|
||||
/// </summary>
|
||||
/// <param name="buffer">数据缓存区</param>
|
||||
/// <param name="timeout">超时时间</param>
|
||||
/// <param name="cancellationToken">取消令箭</param>
|
||||
/// <exception cref="NotConnectedException">客户端没有连接</exception>
|
||||
/// <exception cref="OverlengthException">发送数据超长</exception>
|
||||
/// <exception cref="Exception">其他异常</exception>
|
||||
/// <returns>返回的数据</returns>
|
||||
ResponsedData SendThenResponse(byte[] buffer, int timeout = 1000 * 5, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// 发送流中的有效数据
|
||||
/// </summary>
|
||||
/// <param name="byteBlock">数据块载体</param>
|
||||
/// <param name="timeout">超时时间</param>
|
||||
/// <param name="cancellationToken">取消令箭</param>
|
||||
/// <exception cref="NotConnectedException">客户端没有连接</exception>
|
||||
/// <exception cref="OverlengthException">发送数据超长</exception>
|
||||
/// <exception cref="Exception">其他异常</exception>
|
||||
/// <returns>返回的数据</returns>
|
||||
ResponsedData SendThenResponse(ByteBlock byteBlock, int timeout = 1000 * 5, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// 异步发送
|
||||
@@ -84,36 +60,12 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
/// <param name="buffer">数据缓存区</param>
|
||||
/// <param name="offset">偏移</param>
|
||||
/// <param name="length">长度</param>
|
||||
/// <param name="timeout">超时时间</param>
|
||||
/// <param name="cancellationToken">取消令箭</param>
|
||||
/// <param name="token">取消令箭</param>
|
||||
/// <exception cref="NotConnectedException">客户端没有连接</exception>
|
||||
/// <exception cref="OverlengthException">发送数据超长</exception>
|
||||
/// <exception cref="Exception">其他异常</exception>
|
||||
/// <returns>返回的数据</returns>
|
||||
Task<ResponsedData> SendThenResponseAsync(byte[] buffer, int offset, int length, int timeout = 1000 * 5, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// 异步发送
|
||||
/// </summary>
|
||||
/// <param name="buffer">数据缓存区</param>
|
||||
/// <param name="timeout">超时时间</param>
|
||||
/// <param name="cancellationToken">取消令箭</param>
|
||||
/// <exception cref="NotConnectedException">客户端没有连接</exception>
|
||||
/// <exception cref="OverlengthException">发送数据超长</exception>
|
||||
/// <exception cref="Exception">其他异常</exception>
|
||||
/// <returns>返回的数据</returns>
|
||||
Task<ResponsedData> SendThenResponseAsync(byte[] buffer, int timeout = 1000 * 5, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// 异步发送
|
||||
/// </summary>
|
||||
/// <param name="byteBlock">数据块载体</param>
|
||||
/// <param name="timeout">超时时间</param>
|
||||
/// <param name="cancellationToken">取消令箭</param>
|
||||
/// <exception cref="NotConnectedException">客户端没有连接</exception>
|
||||
/// <exception cref="OverlengthException">发送数据超长</exception>
|
||||
/// <exception cref="Exception">其他异常</exception>
|
||||
/// <returns>返回的数据</returns>
|
||||
Task<ResponsedData> SendThenResponseAsync(ByteBlock byteBlock, int timeout = 1000 * 5, CancellationToken cancellationToken = default);
|
||||
Task<ResponsedData> SendThenResponseAsync(byte[] buffer, int offset, int length, CancellationToken token);
|
||||
}
|
||||
|
||||
}
|
@@ -27,17 +27,11 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
{
|
||||
internal class WaitingClient<TClient> : DisposableObject, IWaitingClient<TClient> where TClient : IClient, ISender
|
||||
{
|
||||
private readonly Func<ResponsedData, bool> m_func;
|
||||
private readonly SemaphoreSlim m_semaphoreSlim = new SemaphoreSlim(1, 1);
|
||||
private readonly EasyLock m_semaphoreSlim = new();
|
||||
private volatile bool m_breaked;
|
||||
private CancellationTokenSource m_cancellation;
|
||||
private CancellationTokenSource m_cancellationTokenSource;
|
||||
|
||||
|
||||
public WaitingClient(TClient client, WaitingOptions waitingOptions, Func<ResponsedData, bool> func)
|
||||
{
|
||||
this.Client = client ?? throw new ArgumentNullException(nameof(client));
|
||||
this.WaitingOptions = waitingOptions;
|
||||
this.m_func = func;
|
||||
}
|
||||
|
||||
public WaitingClient(TClient client, WaitingOptions waitingOptions)
|
||||
{
|
||||
@@ -59,19 +53,25 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
this.Client = default;
|
||||
this.Cancel();
|
||||
this.Client = default;
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
private void Cancel()
|
||||
{
|
||||
this.m_cancellation.Cancel();
|
||||
try
|
||||
{
|
||||
this.m_cancellationTokenSource?.Cancel();
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
#region 同步Response
|
||||
|
||||
public ResponsedData SendThenResponse(byte[] buffer, int offset, int length, int timeout = 1000 * 5, CancellationToken token = default)
|
||||
public ResponsedData SendThenResponse(byte[] buffer, int offset, int length, CancellationToken token = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -79,14 +79,13 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
this.m_breaked = false;
|
||||
if (token.CanBeCanceled)
|
||||
{
|
||||
using CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(timeout);
|
||||
m_cancellation = CancellationTokenSource.CreateLinkedTokenSource(cancellationTokenSource.Token, token);
|
||||
this.m_cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(token);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_cancellation = new CancellationTokenSource(timeout);
|
||||
this.m_cancellationTokenSource = new CancellationTokenSource(5000);
|
||||
}
|
||||
using (m_cancellation)
|
||||
using (m_cancellationTokenSource)
|
||||
{
|
||||
if (this.WaitingOptions.RemoteIPHost != null && this.Client is IUdpSession session)
|
||||
{
|
||||
@@ -96,7 +95,7 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
|
||||
while (true)
|
||||
{
|
||||
using (var receiverResult = receiver.ReadAsync(m_cancellation.Token).GetFalseAwaitResult())
|
||||
using (var receiverResult = receiver.ReadAsync(this.m_cancellationTokenSource.Token).GetFalseAwaitResult())
|
||||
{
|
||||
var response = new ResponsedData(receiverResult.ByteBlock?.ToArray(), receiverResult.RequestInfo);
|
||||
}
|
||||
@@ -110,7 +109,7 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
this.Client.Send(buffer, offset, length);
|
||||
while (true)
|
||||
{
|
||||
using (var receiverResult = receiver.ReadAsync(m_cancellation.Token).GetFalseAwaitResult())
|
||||
using (var receiverResult = receiver.ReadAsync(this.m_cancellationTokenSource.Token).GetFalseAwaitResult())
|
||||
{
|
||||
if (receiverResult.IsClosed)
|
||||
{
|
||||
@@ -119,13 +118,13 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
}
|
||||
var response = new ResponsedData(receiverResult.ByteBlock?.ToArray(), receiverResult.RequestInfo);
|
||||
|
||||
if (this.m_func == null)
|
||||
if (this.WaitingOptions.FilterFunc == null)
|
||||
{
|
||||
return response;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.m_func.Invoke(response))
|
||||
if (this.WaitingOptions.FilterFunc.Invoke(response))
|
||||
{
|
||||
return response;
|
||||
}
|
||||
@@ -142,25 +141,18 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.m_cancellationTokenSource = null;
|
||||
this.m_semaphoreSlim.Release();
|
||||
}
|
||||
}
|
||||
|
||||
public ResponsedData SendThenResponse(byte[] buffer, int timeout = 1000 * 5, CancellationToken token = default)
|
||||
{
|
||||
return this.SendThenResponse(buffer, 0, buffer.Length, timeout, token);
|
||||
}
|
||||
|
||||
public ResponsedData SendThenResponse(ByteBlock byteBlock, int timeout = 1000 * 5, CancellationToken token = default)
|
||||
{
|
||||
return this.SendThenResponse(byteBlock.Buffer, 0, byteBlock.Len, timeout, token);
|
||||
}
|
||||
|
||||
#endregion 同步Response
|
||||
|
||||
#region Response异步
|
||||
|
||||
public async Task<ResponsedData> SendThenResponseAsync(byte[] buffer, int offset, int length, int timeout = 1000 * 5, CancellationToken token = default)
|
||||
public async Task<ResponsedData> SendThenResponseAsync(byte[] buffer, int offset, int length, CancellationToken token = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -168,14 +160,13 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
this.m_breaked = false;
|
||||
if (token.CanBeCanceled)
|
||||
{
|
||||
using CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(timeout);
|
||||
m_cancellation = CancellationTokenSource.CreateLinkedTokenSource(cancellationTokenSource.Token, token);
|
||||
this.m_cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(token);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_cancellation = new CancellationTokenSource(timeout);
|
||||
this.m_cancellationTokenSource = new CancellationTokenSource(5000);
|
||||
}
|
||||
using (m_cancellation)
|
||||
using (m_cancellationTokenSource)
|
||||
{
|
||||
if (this.WaitingOptions.RemoteIPHost != null && this.Client is IUdpSession session)
|
||||
{
|
||||
@@ -185,7 +176,7 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
|
||||
while (true)
|
||||
{
|
||||
using (var receiverResult = await receiver.ReadAsync(m_cancellation.Token))
|
||||
using (var receiverResult = await receiver.ReadAsync(m_cancellationTokenSource.Token))
|
||||
{
|
||||
var response = new ResponsedData(receiverResult.ByteBlock?.ToArray(), receiverResult.RequestInfo);
|
||||
}
|
||||
@@ -199,7 +190,7 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
await this.Client.SendAsync(buffer, offset, length);
|
||||
while (true)
|
||||
{
|
||||
using (var receiverResult = await receiver.ReadAsync(m_cancellation.Token))
|
||||
using (var receiverResult = await receiver.ReadAsync(this.m_cancellationTokenSource.Token))
|
||||
{
|
||||
if (receiverResult.IsClosed)
|
||||
{
|
||||
@@ -208,13 +199,13 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
}
|
||||
var response = new ResponsedData(receiverResult.ByteBlock?.ToArray(), receiverResult.RequestInfo);
|
||||
|
||||
if (this.m_func == null)
|
||||
if (this.WaitingOptions.FilterFunc == null)
|
||||
{
|
||||
return response;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.m_func.Invoke(response))
|
||||
if (this.WaitingOptions.FilterFunc.Invoke(response))
|
||||
{
|
||||
return response;
|
||||
}
|
||||
@@ -231,58 +222,27 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.m_cancellationTokenSource = null;
|
||||
this.m_semaphoreSlim.Release();
|
||||
}
|
||||
}
|
||||
|
||||
public Task<ResponsedData> SendThenResponseAsync(byte[] buffer, int timeout = 1000 * 5, CancellationToken token = default)
|
||||
{
|
||||
return this.SendThenResponseAsync(buffer, 0, buffer.Length, timeout, token);
|
||||
}
|
||||
|
||||
public Task<ResponsedData> SendThenResponseAsync(ByteBlock byteBlock, int timeout = 1000 * 5, CancellationToken token = default)
|
||||
{
|
||||
return this.SendThenResponseAsync(byteBlock.Buffer, 0, byteBlock.Len, timeout, token);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endregion Response异步
|
||||
|
||||
#region 字节同步
|
||||
|
||||
public byte[] SendThenReturn(byte[] buffer, int offset, int length, int timeout = 1000 * 5, CancellationToken token = default)
|
||||
public byte[] SendThenReturn(byte[] buffer, int offset, int length, CancellationToken token = default)
|
||||
{
|
||||
return this.SendThenResponse(buffer, offset, length, timeout, token).Data;
|
||||
return this.SendThenResponse(buffer, offset, length, token).Data;
|
||||
}
|
||||
|
||||
public byte[] SendThenReturn(byte[] buffer, int timeout = 1000 * 5, CancellationToken token = default)
|
||||
public async Task<byte[]> SendThenReturnAsync(byte[] buffer, int offset, int length, CancellationToken token = default)
|
||||
{
|
||||
return this.SendThenReturn(buffer, 0, buffer.Length, timeout, token);
|
||||
return (await this.SendThenResponseAsync(buffer, offset, length, token)).Data;
|
||||
}
|
||||
|
||||
public byte[] SendThenReturn(ByteBlock byteBlock, int timeout = 1000 * 5, CancellationToken token = default)
|
||||
{
|
||||
return this.SendThenReturn(byteBlock.Buffer, 0, byteBlock.Len, timeout, token);
|
||||
}
|
||||
|
||||
#endregion 字节同步
|
||||
|
||||
#region 字节异步
|
||||
|
||||
public async Task<byte[]> SendThenReturnAsync(byte[] buffer, int offset, int length, int timeout = 1000 * 5, CancellationToken token = default)
|
||||
{
|
||||
return (await this.SendThenResponseAsync(buffer, offset, length, timeout, token)).Data;
|
||||
}
|
||||
|
||||
public async Task<byte[]> SendThenReturnAsync(byte[] buffer, int timeout = 1000 * 5, CancellationToken token = default)
|
||||
{
|
||||
return (await this.SendThenResponseAsync(buffer, 0, buffer.Length, timeout, token)).Data;
|
||||
}
|
||||
|
||||
public async Task<byte[]> SendThenReturnAsync(ByteBlock byteBlock, int timeout = 1000 * 5, CancellationToken token = default)
|
||||
{
|
||||
return (await this.SendThenResponseAsync(byteBlock.Buffer, 0, byteBlock.Len, timeout, token)).Data;
|
||||
}
|
||||
|
||||
#endregion 字节异步
|
||||
}
|
||||
}
|
@@ -23,6 +23,8 @@
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System.Text;
|
||||
|
||||
namespace ThingsGateway.Foundation.Sockets
|
||||
{
|
||||
/// <summary>
|
||||
@@ -31,28 +33,224 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
public static class WaitingClientExtension
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取筛选条件的可等待的客户端。
|
||||
/// </summary>
|
||||
/// <typeparam name="TClient"></typeparam>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="waitingOptions"></param>
|
||||
/// <param name="func">当条件成立时返回</param>
|
||||
/// <returns></returns>
|
||||
public static IWaitingClient<TClient> GetWaitingClient<TClient>(this TClient client, WaitingOptions waitingOptions, Func<ResponsedData, bool> func) where TClient : IClient, ISender
|
||||
{
|
||||
return new WaitingClient<TClient>(client, waitingOptions, func);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取可等待的客户端。
|
||||
/// 创建可等待的客户端。
|
||||
/// </summary>
|
||||
/// <typeparam name="TClient"></typeparam>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="waitingOptions"></param>
|
||||
/// <returns></returns>
|
||||
public static IWaitingClient<TClient> GetWaitingClient<TClient>(this TClient client, WaitingOptions waitingOptions) where TClient : IClient, ISender
|
||||
public static IWaitingClient<TClient> CreateWaitingClient<TClient>(this TClient client, WaitingOptions waitingOptions) where TClient : IClient, ISender
|
||||
{
|
||||
return new WaitingClient<TClient>(client, waitingOptions);
|
||||
}
|
||||
|
||||
#region 发送
|
||||
|
||||
/// <summary>
|
||||
/// 发送数据并等待
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="buffer">数据缓存区</param>
|
||||
/// <param name="token">取消令箭</param>
|
||||
/// <exception cref="NotConnectedException">客户端没有连接</exception>
|
||||
/// <exception cref="OverlengthException">发送数据超长</exception>
|
||||
/// <exception cref="Exception">其他异常</exception>
|
||||
/// <returns>返回的数据</returns>
|
||||
public static ResponsedData SendThenResponse<TClient>(this IWaitingClient<TClient> client, byte[] buffer, CancellationToken token)
|
||||
where TClient : IClient, ISender
|
||||
{
|
||||
return client.SendThenResponse(buffer, 0, buffer.Length, token);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送数据并等待
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="msg"></param>
|
||||
/// <param name="token">取消令箭</param>
|
||||
/// <exception cref="NotConnectedException">客户端没有连接</exception>
|
||||
/// <exception cref="OverlengthException">发送数据超长</exception>
|
||||
/// <exception cref="Exception">其他异常</exception>
|
||||
/// <returns>返回的数据</returns>
|
||||
public static ResponsedData SendThenResponse<TClient>(this IWaitingClient<TClient> client, string msg, CancellationToken token)
|
||||
where TClient : IClient, ISender
|
||||
{
|
||||
return client.SendThenResponse(Encoding.UTF8.GetBytes(msg), token);
|
||||
}
|
||||
/// <summary>
|
||||
/// 发送数据并等待
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="buffer">数据缓存区</param>
|
||||
/// <param name="timeout">超时时间</param>
|
||||
/// <param name="token">取消令箭</param>
|
||||
/// <exception cref="NotConnectedException">客户端没有连接</exception>
|
||||
/// <exception cref="OverlengthException">发送数据超长</exception>
|
||||
/// <exception cref="Exception">其他异常</exception>
|
||||
/// <returns>返回的数据</returns>
|
||||
public static ResponsedData SendThenResponse<TClient>(this IWaitingClient<TClient> client, byte[] buffer, int timeout, CancellationToken token)
|
||||
where TClient : IClient, ISender
|
||||
{
|
||||
using CancellationTokenSource cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(new CancellationTokenSource(timeout).Token, token);
|
||||
return client.SendThenResponse(buffer, 0, buffer.Length, cancellationTokenSource.Token);
|
||||
}
|
||||
/// <summary>
|
||||
/// 发送数据并等待
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="buffer">数据缓存区</param>
|
||||
/// <param name="timeout">超时时间</param>
|
||||
/// <param name="token">取消令箭</param>
|
||||
/// <exception cref="NotConnectedException">客户端没有连接</exception>
|
||||
/// <exception cref="OverlengthException">发送数据超长</exception>
|
||||
/// <exception cref="Exception">其他异常</exception>
|
||||
/// <returns>返回的数据</returns>
|
||||
public static Task<ResponsedData> SendThenResponseAsync<TClient>(this IWaitingClient<TClient> client, byte[] buffer, int timeout, CancellationToken token)
|
||||
where TClient : IClient, ISender
|
||||
{
|
||||
using CancellationTokenSource cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(new CancellationTokenSource(timeout).Token, token);
|
||||
return client.SendThenResponseAsync(buffer, 0, buffer.Length, cancellationTokenSource.Token);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送数据并等待
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="msg"></param>
|
||||
/// <param name="timeout"></param>
|
||||
/// <exception cref="NotConnectedException">客户端没有连接</exception>
|
||||
/// <exception cref="OverlengthException">发送数据超长</exception>
|
||||
/// <exception cref="Exception">其他异常</exception>
|
||||
/// <returns>返回的数据</returns>
|
||||
public static ResponsedData SendThenResponse<TClient>(this IWaitingClient<TClient> client, string msg, int timeout = 5000)
|
||||
where TClient : IClient, ISender
|
||||
{
|
||||
return client.SendThenResponse(Encoding.UTF8.GetBytes(msg), timeout);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送数据并等待
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="byteBlock">数据块载体</param>
|
||||
/// <param name="token">取消令箭</param>
|
||||
/// <exception cref="NotConnectedException">客户端没有连接</exception>
|
||||
/// <exception cref="OverlengthException">发送数据超长</exception>
|
||||
/// <exception cref="Exception">其他异常</exception>
|
||||
/// <returns>返回的数据</returns>
|
||||
public static ResponsedData SendThenResponse<TClient>(this IWaitingClient<TClient> client, ByteBlock byteBlock, CancellationToken token)
|
||||
where TClient : IClient, ISender
|
||||
{
|
||||
return client.SendThenResponse(byteBlock.Buffer, 0, byteBlock.Len, token);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送数据并等待
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="buffer">数据缓存区</param>
|
||||
/// <param name="timeout">超时时间</param>
|
||||
/// <exception cref="NotConnectedException">客户端没有连接</exception>
|
||||
/// <exception cref="OverlengthException">发送数据超长</exception>
|
||||
/// <exception cref="Exception">其他异常</exception>
|
||||
/// <returns>返回的数据</returns>
|
||||
public static ResponsedData SendThenResponse<TClient>(this IWaitingClient<TClient> client, byte[] buffer, int timeout = 5000)
|
||||
where TClient : IClient, ISender
|
||||
{
|
||||
using (var tokenSource = new CancellationTokenSource(timeout))
|
||||
{
|
||||
return client.SendThenResponse(buffer, 0, buffer.Length, tokenSource.Token);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送数据并等待
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="byteBlock">数据块载体</param>
|
||||
/// <param name="timeout">超时时间</param>
|
||||
/// <exception cref="NotConnectedException">客户端没有连接</exception>
|
||||
/// <exception cref="OverlengthException">发送数据超长</exception>
|
||||
/// <exception cref="Exception">其他异常</exception>
|
||||
/// <returns>返回的数据</returns>
|
||||
public static ResponsedData SendThenResponse<TClient>(this IWaitingClient<TClient> client, ByteBlock byteBlock, int timeout = 5000)
|
||||
where TClient : IClient, ISender
|
||||
{
|
||||
using (var tokenSource = new CancellationTokenSource(timeout))
|
||||
{
|
||||
return client.SendThenResponse(byteBlock.Buffer, 0, byteBlock.Len, tokenSource.Token);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送数据并等待
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="buffer"></param>
|
||||
/// <param name="token">取消令箭</param>
|
||||
/// <exception cref="NotConnectedException">客户端没有连接</exception>
|
||||
/// <exception cref="OverlengthException">发送数据超长</exception>
|
||||
/// <exception cref="Exception">其他异常</exception>
|
||||
/// <returns>返回的数据</returns>
|
||||
public static Task<ResponsedData> SendThenResponseAsync<TClient>(this IWaitingClient<TClient> client, byte[] buffer, CancellationToken token)
|
||||
where TClient : IClient, ISender
|
||||
{
|
||||
return client.SendThenResponseAsync(buffer, 0, buffer.Length, token);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送数据并等待
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="msg"></param>
|
||||
/// <param name="token">取消令箭</param>
|
||||
/// <exception cref="NotConnectedException">客户端没有连接</exception>
|
||||
/// <exception cref="OverlengthException">发送数据超长</exception>
|
||||
/// <exception cref="Exception">其他异常</exception>
|
||||
/// <returns>返回的数据</returns>
|
||||
public static Task<ResponsedData> SendThenResponseAsync<TClient>(this IWaitingClient<TClient> client, string msg, CancellationToken token)
|
||||
where TClient : IClient, ISender
|
||||
{
|
||||
return client.SendThenResponseAsync(Encoding.UTF8.GetBytes(msg), token);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送数据并等待
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="buffer"></param>
|
||||
/// <param name="timeout">超时时间</param>
|
||||
/// <exception cref="NotConnectedException">客户端没有连接</exception>
|
||||
/// <exception cref="OverlengthException">发送数据超长</exception>
|
||||
/// <exception cref="Exception">其他异常</exception>
|
||||
/// <returns>返回的数据</returns>
|
||||
public static Task<ResponsedData> SendThenResponseAsync<TClient>(this IWaitingClient<TClient> client, byte[] buffer, int timeout = 5000)
|
||||
where TClient : IClient, ISender
|
||||
{
|
||||
using (var tokenSource = new CancellationTokenSource(timeout))
|
||||
{
|
||||
return client.SendThenResponseAsync(buffer, 0, buffer.Length, tokenSource.Token);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送数据并等待
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="msg"></param>
|
||||
/// <param name="timeout">超时时间</param>
|
||||
/// <exception cref="NotConnectedException">客户端没有连接</exception>
|
||||
/// <exception cref="OverlengthException">发送数据超长</exception>
|
||||
/// <exception cref="Exception">其他异常</exception>
|
||||
/// <returns>返回的数据</returns>
|
||||
public static Task<ResponsedData> SendThenResponseAsync<TClient>(this IWaitingClient<TClient> client, string msg, int timeout = 5000)
|
||||
where TClient : IClient, ISender
|
||||
{
|
||||
using (var tokenSource = new CancellationTokenSource(timeout))
|
||||
{
|
||||
return client.SendThenResponseAsync(Encoding.UTF8.GetBytes(msg), tokenSource.Token);
|
||||
}
|
||||
}
|
||||
#endregion 发送
|
||||
}
|
||||
}
|
@@ -45,5 +45,12 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
/// 当Client为Tcp系时。是否在断开连接时以异常返回结果。
|
||||
/// </summary>
|
||||
public bool ThrowBreakException { get; set; } = true;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 筛选函数
|
||||
/// </summary>
|
||||
public Func<ResponsedData, bool> FilterFunc { get; set; }
|
||||
|
||||
}
|
||||
}
|
@@ -142,7 +142,7 @@ namespace ThingsGateway.Foundation.WebApi
|
||||
catch (Exception ex)
|
||||
{
|
||||
invokeResult.Status = InvokeStatus.Exception;
|
||||
invokeResult.Message = ex.Message;
|
||||
invokeResult.Message = ex.ToString();
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -273,7 +273,7 @@ namespace ThingsGateway.Foundation.WebApi
|
||||
catch (Exception ex)
|
||||
{
|
||||
invokeResult.Status = InvokeStatus.Exception;
|
||||
invokeResult.Message = ex.Message;
|
||||
invokeResult.Message = ex.ToString();
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<Version>3.0.0.12</Version>
|
||||
<Version>3.0.0.22</Version>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
|
||||
|
@@ -98,7 +98,7 @@ public class KafkaProducer : UpLoadBase
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage.LogWarning(ex, ToString());
|
||||
LogMessage.LogWarning(ex);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -133,7 +133,7 @@ public class KafkaProducer : UpLoadBase
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage.LogWarning(ex, ToString());
|
||||
LogMessage.LogWarning(ex);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -144,7 +144,7 @@ public class KafkaProducer : UpLoadBase
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex, ToString());
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -153,7 +153,7 @@ public class KafkaProducer : UpLoadBase
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex, ToString());
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
try
|
||||
{
|
||||
@@ -180,7 +180,7 @@ public class KafkaProducer : UpLoadBase
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex, ToString());
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
}
|
||||
if (isSuccess)
|
||||
@@ -212,7 +212,7 @@ public class KafkaProducer : UpLoadBase
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex, ToString());
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
}
|
||||
if (isSuccess)
|
||||
@@ -226,7 +226,7 @@ public class KafkaProducer : UpLoadBase
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex, ToString());
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
|
||||
if (driverPropertys.CycleInterval > UploadDeviceThread.CycleInterval + 50)
|
||||
@@ -401,7 +401,7 @@ public class KafkaProducer : UpLoadBase
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex, ToString());
|
||||
LogMessage?.LogWarning(ex);
|
||||
await CacheDb.AddCacheData(topic, payLoad, driverPropertys.CacheMaxCount);
|
||||
}
|
||||
}
|
||||
|
@@ -162,7 +162,7 @@ public class ModbusSerialServer : UpLoadBase
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex, ToString());
|
||||
LogMessage?.LogWarning(ex);
|
||||
tags.ForEach(a =>
|
||||
{
|
||||
a.VariableValueChange -= VariableValueChange;
|
||||
@@ -234,7 +234,7 @@ public class ModbusSerialServer : UpLoadBase
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new OperResult(ex.Message);
|
||||
return new OperResult(ex);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -158,7 +158,7 @@ public class ModbusTcpServer : UpLoadBase
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex, ToString());
|
||||
LogMessage?.LogWarning(ex);
|
||||
tags.ForEach(a =>
|
||||
{
|
||||
a.VariableValueChange -= VariableValueChange;
|
||||
@@ -201,7 +201,7 @@ public class ModbusTcpServer : UpLoadBase
|
||||
var addressStr = GetPropertyValue(tag.Value, nameof(ModbusTcpServerVariableProperty.ServiceAddress));
|
||||
if (Enum.TryParse<DataTypeEnum>(type, out DataTypeEnum result))
|
||||
{
|
||||
var result1 = await RpcCore.InvokeDeviceMethodAsync($"{nameof(ModbusTcpServer)}-{CurrentDevice.Name}-{client.IP + ":" + client.Port}",
|
||||
var result1 = await RpcCore.InvokeDeviceMethodAsync($"{nameof(ModbusTcpServer)}-{CurrentDevice.Name}-{$"{client.IP}:{client.Port}"}",
|
||||
new Dictionary<string, string>
|
||||
{
|
||||
{
|
||||
@@ -216,7 +216,7 @@ public class ModbusTcpServer : UpLoadBase
|
||||
}
|
||||
else
|
||||
{
|
||||
var result1 = await RpcCore.InvokeDeviceMethodAsync($"{nameof(ModbusTcpServer)}-{CurrentDevice.Name}-{client.IP + ":" + client.Port}",
|
||||
var result1 = await RpcCore.InvokeDeviceMethodAsync($"{nameof(ModbusTcpServer)}-{CurrentDevice.Name}-{$"{client.IP}:{client.Port}"}",
|
||||
new Dictionary<string, string>
|
||||
{
|
||||
{
|
||||
@@ -230,7 +230,7 @@ public class ModbusTcpServer : UpLoadBase
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new OperResult(ex.Message);
|
||||
return new OperResult(ex);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -124,7 +124,7 @@ public class IotSharpClient : UpLoadBase
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex, ToString());
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -163,7 +163,7 @@ public class IotSharpClient : UpLoadBase
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex, ToString());
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -171,7 +171,7 @@ public class IotSharpClient : UpLoadBase
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex, ToString());
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -180,7 +180,7 @@ public class IotSharpClient : UpLoadBase
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex, ToString());
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
try
|
||||
{
|
||||
@@ -207,7 +207,7 @@ public class IotSharpClient : UpLoadBase
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex, ToString());
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -237,7 +237,7 @@ public class IotSharpClient : UpLoadBase
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex, ToString());
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -250,7 +250,7 @@ public class IotSharpClient : UpLoadBase
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex, ToString());
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
|
||||
if (driverPropertys.CycleInterval > UploadDeviceThread.CycleInterval + 50)
|
||||
@@ -301,7 +301,7 @@ public class IotSharpClient : UpLoadBase
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogError(ex, ToString());
|
||||
LogMessage?.LogError(ex);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -114,7 +114,7 @@ public class MqttClient : UpLoadBase
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex, ToString());
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -149,7 +149,7 @@ public class MqttClient : UpLoadBase
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex, ToString());
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -157,7 +157,7 @@ public class MqttClient : UpLoadBase
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex, ToString());
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -167,7 +167,7 @@ public class MqttClient : UpLoadBase
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex, ToString());
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
try
|
||||
{
|
||||
@@ -194,7 +194,7 @@ public class MqttClient : UpLoadBase
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex, ToString());
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -226,7 +226,7 @@ public class MqttClient : UpLoadBase
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex, ToString());
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -239,7 +239,7 @@ public class MqttClient : UpLoadBase
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex, ToString());
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
|
||||
if (driverPropertys.CycleInterval > UploadDeviceThread.CycleInterval + 50)
|
||||
@@ -293,7 +293,7 @@ public class MqttClient : UpLoadBase
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogError(ex, ToString());
|
||||
LogMessage?.LogError(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -438,7 +438,7 @@ public class MqttClient : UpLoadBase
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex, ToString());
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
try
|
||||
{
|
||||
|
@@ -108,7 +108,7 @@ public class MqttServer : UpLoadBase
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex, ToString());
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -117,7 +117,7 @@ public class MqttServer : UpLoadBase
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex, ToString());
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
|
||||
try
|
||||
@@ -147,7 +147,7 @@ public class MqttServer : UpLoadBase
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex, ToString());
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -157,7 +157,7 @@ public class MqttServer : UpLoadBase
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex, ToString());
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
|
||||
try
|
||||
@@ -170,7 +170,7 @@ public class MqttServer : UpLoadBase
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex, ToString());
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
if (driverPropertys.CycleInterval > UploadDeviceThread.CycleInterval + 50)
|
||||
{
|
||||
@@ -302,7 +302,7 @@ public class MqttServer : UpLoadBase
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex, ToString());
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
try
|
||||
{
|
||||
|
@@ -88,12 +88,12 @@ f =>
|
||||
.Build();
|
||||
|
||||
await mqttClientPage.MqttClient.SubscribeAsync(mqttSubscribeOptions, CancellationToken.None);
|
||||
driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Information, DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(driverDebugUIPage.InitTimezone.TimezoneOffset) + " - " + $"订阅{driverDebugUIPage.Address}成功"));
|
||||
driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Information, $"{DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(driverDebugUIPage.InitTimezone.TimezoneOffset)} - 订阅{driverDebugUIPage.Address}成功"));
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Error, DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(driverDebugUIPage.InitTimezone.TimezoneOffset) + " - " + ex.Message));
|
||||
driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Error, $"{DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(driverDebugUIPage.InitTimezone.TimezoneOffset)} - {ex}"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -106,12 +106,12 @@ f =>
|
||||
.Build();
|
||||
|
||||
await mqttClientPage.MqttClient.UnsubscribeAsync(mqttSubscribeOptions, CancellationToken.None);
|
||||
driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Information, DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(driverDebugUIPage.InitTimezone.TimezoneOffset) + " - " + $"取消订阅{driverDebugUIPage.Address}成功"));
|
||||
driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Information, $"{DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(driverDebugUIPage.InitTimezone.TimezoneOffset)} - 取消订阅{driverDebugUIPage.Address}成功"));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Error, DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(driverDebugUIPage.InitTimezone.TimezoneOffset) + " - " + ex.Message));
|
||||
driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Error, $"{DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(driverDebugUIPage.InitTimezone.TimezoneOffset)} - {ex}"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -125,11 +125,11 @@ f =>
|
||||
.WithTopic($"{PublishTopic}")
|
||||
.WithPayload(PublishValue).Build();
|
||||
await mqttClientPage.MqttClient.PublishAsync(devMessage, CancellationToken.None);
|
||||
driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Information, DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(driverDebugUIPage.InitTimezone.TimezoneOffset) + " - " + $"发布{PublishTopic}成功"));
|
||||
driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Information, $"{DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(driverDebugUIPage.InitTimezone.TimezoneOffset)} - 发布{PublishTopic}成功"));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Error, DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(driverDebugUIPage.InitTimezone.TimezoneOffset) + " - " + ex.Message));
|
||||
driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Error, $"{DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(driverDebugUIPage.InitTimezone.TimezoneOffset)} - {ex}"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -141,11 +141,11 @@ f =>
|
||||
using MqttRpcClient mqttRpcClient = new(mqttClientPage.MqttClient);
|
||||
var data = await mqttRpcClient.ExecuteAsync(MqttRpcTopicPair, driverDebugUIPage.WriteValue, MQTTnet.Protocol.MqttQualityOfServiceLevel.AtMostOnce, TimeSpan.FromSeconds(10));
|
||||
var str = Encoding.UTF8.GetString(data);
|
||||
driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Information, DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(driverDebugUIPage.InitTimezone.TimezoneOffset) + " - " + str));
|
||||
driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Information, $"{DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(driverDebugUIPage.InitTimezone.TimezoneOffset)} - {str}"));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Error, DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(driverDebugUIPage.InitTimezone.TimezoneOffset) + " - " + ex.Message));
|
||||
driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Error, $"{DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(driverDebugUIPage.InitTimezone.TimezoneOffset)} - {ex}"));
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -230,7 +230,7 @@ public class OPCDAClient : CollectBase
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex, ToString());
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -86,7 +86,7 @@ public partial class OPCDAClientDebugPage : IDisposable
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Warning, DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset) + " - " + ex.Message));
|
||||
driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Warning, $"{DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset)} - {ex}"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,7 +182,7 @@ public partial class OPCDAClientDebugPage : IDisposable
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Warning, DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset) + " - " + ex.Message));
|
||||
driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Warning, $"{DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset)} - {ex}"));
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
@@ -228,7 +228,7 @@ public partial class OPCDAClientDebugPage : IDisposable
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Error, DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset) + " - " + "写入失败:" + ex.Message));
|
||||
driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Error, $"{DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset)} - 写入失败:{ex}"));
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
|
@@ -177,6 +177,8 @@ public class OPCUAClient : CollectBase
|
||||
if (_plc != null)
|
||||
{
|
||||
_plc.DataChangedHandler -= DataChangedHandler;
|
||||
_plc.OpcStatusChange -= _plc_OpcStatusChange;
|
||||
|
||||
_plc.Disconnect();
|
||||
_plc.SafeDispose();
|
||||
_plc = null;
|
||||
@@ -204,13 +206,19 @@ public class OPCUAClient : CollectBase
|
||||
};
|
||||
if (_plc == null)
|
||||
{
|
||||
_plc = new((arg1, arg2, arg3, arg4) => Log_Out((LogLevel)arg1, arg2, arg3, arg4));
|
||||
_plc = new();
|
||||
_plc.OpcStatusChange += _plc_OpcStatusChange;
|
||||
_plc.DataChangedHandler += DataChangedHandler;
|
||||
}
|
||||
|
||||
_plc.OPCNode = opcNode;
|
||||
}
|
||||
|
||||
private void _plc_OpcStatusChange(object sender, OpcUaStatusEventArgs e)
|
||||
{
|
||||
Log_Out((LogLevel)e.LogLevel, null, e.Text, null);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override Task<OperResult<byte[]>> ReadAsync(string address, int length, CancellationToken cancellationToken)
|
||||
{
|
||||
@@ -283,7 +291,7 @@ public class OPCUAClient : CollectBase
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex, ToString());
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -0,0 +1,39 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using Opc.Ua.Configuration;
|
||||
|
||||
namespace ThingsGateway.Plugin.OPCUA;
|
||||
|
||||
|
||||
public partial class OPCUAServer
|
||||
{
|
||||
public class ApplicationMessageDlg : IApplicationMessageDlg
|
||||
{
|
||||
private string message = string.Empty;
|
||||
private ILog _log;
|
||||
public ApplicationMessageDlg(ILog log)
|
||||
{
|
||||
_log = log;
|
||||
}
|
||||
public override void Message(string text, bool ask)
|
||||
{
|
||||
message = text;
|
||||
}
|
||||
|
||||
public override async Task<bool> ShowAsync()
|
||||
{
|
||||
_log.Warning(message);
|
||||
return await Task.FromResult(true);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,59 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace ThingsGateway.Plugin.OPCUA;
|
||||
|
||||
|
||||
public partial class OPCUAServer
|
||||
{
|
||||
private class OPCUALogger : ILogger
|
||||
{
|
||||
private ILog _log;
|
||||
public OPCUALogger(ILog log)
|
||||
{
|
||||
_log = log;
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// Set the log level
|
||||
/// </summary>
|
||||
public Microsoft.Extensions.Logging.LogLevel LogLevel { get; set; } = Microsoft.Extensions.Logging.LogLevel.Trace;
|
||||
/// <inheritdoc/>
|
||||
public IDisposable BeginScope<TState>(TState state) => default;
|
||||
/// <inheritdoc/>
|
||||
public bool IsEnabled(Microsoft.Extensions.Logging.LogLevel logLevel) => logLevel >= LogLevel;
|
||||
/// <inheritdoc/>
|
||||
public void Log<TState>(
|
||||
Microsoft.Extensions.Logging.LogLevel logLevel,
|
||||
EventId eventId,
|
||||
TState state,
|
||||
Exception exception,
|
||||
Func<TState, Exception, string> formatter)
|
||||
{
|
||||
if (!IsEnabled(logLevel))
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
var message = formatter(state, exception);
|
||||
_log.Log((Foundation.Core.LogLevel)(byte)logLevel, state, message, exception);
|
||||
if (logLevel > Microsoft.Extensions.Logging.LogLevel.Information)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -63,7 +63,7 @@ public partial class OPCUAServer : UpLoadBase
|
||||
public override async Task BeforStartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
// 启动服务器。
|
||||
await m_application.CheckApplicationInstanceCertificate(true, 0, 1200);
|
||||
await m_application.CheckApplicationInstanceCertificate(false, 0, 1200);
|
||||
await m_application.Start(m_server);
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
@@ -90,7 +90,7 @@ public partial class OPCUAServer : UpLoadBase
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage.LogWarning(ex, ToString());
|
||||
LogMessage.LogWarning(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,7 +98,7 @@ public partial class OPCUAServer : UpLoadBase
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage.LogWarning(ex, ToString());
|
||||
LogMessage.LogWarning(ex);
|
||||
}
|
||||
if (driverPropertys.CycleInterval > UploadDeviceThread.CycleInterval + 50)
|
||||
{
|
||||
@@ -138,9 +138,13 @@ public partial class OPCUAServer : UpLoadBase
|
||||
_uploadVariables = null;
|
||||
CollectVariableRunTimes.Clear();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Init(UploadDeviceRunTime device)
|
||||
{
|
||||
ApplicationInstance.MessageDlg = new ApplicationMessageDlg(LogMessage);//默认返回true
|
||||
|
||||
//Utils.SetLogger(new OPCUALogger(LogMessage)); //调试用途
|
||||
m_application = new ApplicationInstance();
|
||||
m_configuration = GetDefaultConfiguration();
|
||||
m_configuration.Validate(ApplicationType.Server).GetAwaiter().GetResult();
|
||||
@@ -169,7 +173,7 @@ public partial class OPCUAServer : UpLoadBase
|
||||
private ApplicationConfiguration GetDefaultConfiguration()
|
||||
{
|
||||
ApplicationConfiguration config = new();
|
||||
string url = driverPropertys.OpcUaStringUrl;
|
||||
var urls = driverPropertys.OpcUaStringUrl.Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries);
|
||||
// 签名及加密验证
|
||||
ServerSecurityPolicyCollection policies = new();
|
||||
var userTokens = new UserTokenPolicyCollection();
|
||||
@@ -242,13 +246,14 @@ public partial class OPCUAServer : UpLoadBase
|
||||
|
||||
config.ApplicationName = "ThingsGateway OPCUAServer";
|
||||
config.ApplicationType = ApplicationType.Server;
|
||||
config.ApplicationUri = Utils.Format(@"urn:{0}:thingsgatewayopcuaserver", System.Net.Dns.GetHostName());
|
||||
config.ApplicationUri = driverPropertys.ApplicationUri;
|
||||
|
||||
|
||||
config.ServerConfiguration = new ServerConfiguration()
|
||||
{
|
||||
// 配置登录的地址
|
||||
BaseAddresses = new string[] { url },
|
||||
BaseAddresses = urls,
|
||||
|
||||
SecurityPolicies = policies,
|
||||
UserTokenPolicies = userTokens,
|
||||
ShutdownDelay = 1,
|
||||
@@ -269,7 +274,7 @@ public partial class OPCUAServer : UpLoadBase
|
||||
MaxNotificationQueueSize = 100, // 为每个被监视项目保存在队列中的最大证书数
|
||||
MaxNotificationsPerPublish = 1000, // 每次发布的最大通知数
|
||||
MinMetadataSamplingInterval = 1000, // 元数据的最小采样间隔
|
||||
MaxRegistrationInterval = 30000, // 两次注册尝试之间的最大时间(以毫秒为单位)
|
||||
MaxRegistrationInterval = -1, // 两次注册尝试之间的最大时间(以毫秒为单位)//不提供注册
|
||||
|
||||
};
|
||||
config.SecurityConfiguration = new SecurityConfiguration()
|
||||
@@ -283,7 +288,8 @@ public partial class OPCUAServer : UpLoadBase
|
||||
{
|
||||
StoreType = CertificateStoreType.X509Store,
|
||||
StorePath = "CurrentUser\\UAServer_ThingsGateway",
|
||||
SubjectName = "CN=ThingsGateway OPCUAServer, C=CN, S=GUANGZHOU, O=ThingsGateway, DC=" + System.Net.Dns.GetHostName(),
|
||||
SubjectName = driverPropertys.SubjectName,
|
||||
//ValidationOptions = CertificateValidationOptions.SuppressHostNameInvalid,
|
||||
},
|
||||
|
||||
TrustedPeerCertificates = new CertificateTrustList()
|
||||
@@ -323,7 +329,7 @@ public partial class OPCUAServer : UpLoadBase
|
||||
|
||||
|
||||
config.CertificateValidator = new CertificateValidator();
|
||||
config.CertificateValidator.Update(config);
|
||||
config.CertificateValidator.Update(config).GetAwaiter().GetResult();
|
||||
config.Extensions = new XmlElementCollection();
|
||||
|
||||
return config;
|
||||
|
@@ -10,6 +10,8 @@
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using Opc.Ua;
|
||||
|
||||
namespace ThingsGateway.Plugin.OPCUA;
|
||||
|
||||
/// <inheritdoc/>
|
||||
@@ -18,8 +20,21 @@ public class OPCUAServerProperty : UpDriverPropertyBase
|
||||
/// <summary>
|
||||
/// 服务地址
|
||||
/// </summary>
|
||||
[DeviceProperty("服务地址", "")]
|
||||
[DeviceProperty("服务地址", "分号分割数组,可设置多个url")]
|
||||
public string OpcUaStringUrl { get; set; } = "opc.tcp://127.0.0.1:49321";
|
||||
/// <summary>
|
||||
/// SubjectName
|
||||
/// </summary>
|
||||
[DeviceProperty("SubjectName", "")]
|
||||
public string SubjectName { get; set; } = "CN=ThingsGateway OPCUAServer, C=CN, S=GUANGZHOU, O=ThingsGateway, DC=" + System.Net.Dns.GetHostName();
|
||||
|
||||
/// <summary>
|
||||
/// ApplicationUri
|
||||
/// </summary>
|
||||
[DeviceProperty("ApplicationUri", "")]
|
||||
public string ApplicationUri { get; set; } = Utils.Format(@"urn:{0}:thingsgatewayopcuaserver", System.Net.Dns.GetHostName());
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 安全策略
|
||||
/// </summary>
|
||||
|
@@ -53,16 +53,23 @@
|
||||
写入
|
||||
</MButton>
|
||||
|
||||
<MButton Class="mx-1 my-3" Color="accent" OnClick="()=>IsShowImportVariableList=!IsShowImportVariableList">
|
||||
<span>查看OPC节点空间</span>
|
||||
</MButton>
|
||||
|
||||
|
||||
</div>
|
||||
<div class="my-1 ml-2">
|
||||
|
||||
<MRow Align="AlignTypes.Center" >
|
||||
|
||||
<MCheckbox HideDetails="@("auto")" @bind-Value=IsShowSubvariable Dense Label="是否显示子变量"/>
|
||||
|
||||
<MButton Class="mx-1" Color="accent" OnClick="()=>IsShowImportVariableList=!IsShowImportVariableList">
|
||||
<span>查看OPC节点空间</span>
|
||||
</MButton>
|
||||
</MRow>
|
||||
</div>
|
||||
|
||||
<MCol Class="my-1 py-1">
|
||||
<MRow NoGutters>
|
||||
<MRow Align="AlignTypes.Center">
|
||||
|
||||
|
||||
|
||||
@@ -115,7 +122,7 @@
|
||||
<ChildContent>
|
||||
@if (IsShowImportVariableList)
|
||||
{
|
||||
<OPCUAImportVariable @ref=ImportVariable PLC="_plc"></OPCUAImportVariable>
|
||||
<OPCUAImportVariable @ref=ImportVariable PLC="_plc" IsShowSubvariable=IsShowSubvariable></OPCUAImportVariable>
|
||||
}
|
||||
</ChildContent>
|
||||
|
||||
@@ -127,5 +134,5 @@
|
||||
|
||||
@code {
|
||||
private readonly List<(string Code, string Language)> _sections = new();
|
||||
|
||||
private bool IsShowSubvariable;
|
||||
}
|
||||
|
@@ -80,7 +80,7 @@ public partial class OPCUAClientDebugPage
|
||||
await _plc.AddSubscriptionAsync(Guid.NewGuid().ToString(), new[] { driverDebugUIPage.Address });
|
||||
else
|
||||
{
|
||||
driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Debug, DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset) + " - " + "未连接"));
|
||||
driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Debug, $"{DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset)} - 未连接"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -186,7 +186,7 @@ public partial class OPCUAClientDebugPage
|
||||
{
|
||||
|
||||
driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Warning,
|
||||
$"{DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset)} - {ex.Message}"));
|
||||
$"{DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset)} - {ex}"));
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -234,7 +234,7 @@ public partial class OPCUAClientDebugPage
|
||||
catch (Exception ex)
|
||||
{
|
||||
driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Error,
|
||||
$"{DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset)} - {ex.Message}"));
|
||||
$"{DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset)} - {ex}"));
|
||||
}
|
||||
}
|
||||
}
|
@@ -37,7 +37,7 @@
|
||||
<MTextField Class="ma-1" Label=@node.DescriptionWithOutSugar(a=>a.UserName) Dense Outlined HideDetails="@("auto")" @bind-Value=@node.UserName />
|
||||
<MTextField Class="ma-1" Label=@node.DescriptionWithOutSugar(a=>a.Password) Dense Outlined HideDetails="@("auto")" @bind-Value=@node.Password />
|
||||
|
||||
<MCheckbox Class="ma-1" Label=@node.DescriptionWithOutSugar(a=>a.ActiveSubscribe) Dense Outlined HideDetails="@("auto")" @bind-Value=@node.ActiveSubscribe />
|
||||
<MCheckbox Class="ma-1" Label=@node.DescriptionWithOutSugar(a=>a.ActiveSubscribe) Dense HideDetails="@("auto")" @bind-Value=@node.ActiveSubscribe />
|
||||
<MCheckbox Class="ma-1" Label=@node.DescriptionWithOutSugar(a=>a.IsUseSecurity) Dense HideDetails="@("auto")" @bind-Value=@node.IsUseSecurity />
|
||||
<MCheckbox Class="ma-1" Label=@node.DescriptionWithOutSugar(a=>a.CheckDomain) Dense HideDetails="@("auto")" @bind-Value=@node.CheckDomain />
|
||||
<MCheckbox Class="ma-1" Label=@node.DescriptionWithOutSugar(a=>a.LoadType) Dense HideDetails="@("auto")" @bind-Value=@node.LoadType />
|
||||
|
@@ -36,16 +36,24 @@ public partial class OPCUAClientPage
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
OPC.OpcStatusChange -= OPC_OpcStatusChange;
|
||||
OPC.SafeDispose();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
OPC = new ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient(LogOut);
|
||||
OPC = new ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient();
|
||||
OPC.OpcStatusChange += OPC_OpcStatusChange;
|
||||
base.OnInitialized();
|
||||
}
|
||||
|
||||
private void OPC_OpcStatusChange(object sender, OpcUaStatusEventArgs e)
|
||||
{
|
||||
if (e.LogLevel > 0)
|
||||
LogAction?.Invoke((LogLevel)e.LogLevel, null, e.Text, null);
|
||||
}
|
||||
|
||||
private async Task ConnectAsync()
|
||||
{
|
||||
try
|
||||
@@ -75,6 +83,4 @@ public partial class OPCUAClientPage
|
||||
return OPC;
|
||||
}
|
||||
|
||||
private void LogOut(byte logLevel, object source, string message, Exception exception) => LogAction?.Invoke((LogLevel)logLevel, source, message, exception);
|
||||
|
||||
}
|
@@ -43,6 +43,11 @@ public partial class OPCUAImportVariable
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient PLC { get; set; }
|
||||
/// <summary>
|
||||
/// 是否显示子变量
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public bool IsShowSubvariable { get; set; }
|
||||
|
||||
private List<ReferenceDescription> Actived
|
||||
{
|
||||
@@ -73,7 +78,7 @@ public partial class OPCUAImportVariable
|
||||
//动态加载子项时,导出内容需要添加手动加载代码
|
||||
foreach (var node in Selected.ToList())
|
||||
{
|
||||
List<OPCUATagModel> nodes = await PopulateBranchAsync((NodeId)node.NodeId, true);
|
||||
List<OPCUATagModel> nodes = await PopulateBranchAsync((NodeId)node.NodeId, true, IsShowSubvariable);
|
||||
if (nodes.Count > 0)
|
||||
{
|
||||
Selected.AddRange(nodes.SelectMany(a => a.GetAllTags()).Select(a => a.Tag).Where(a => a != null).ToList());
|
||||
@@ -165,7 +170,7 @@ public partial class OPCUAImportVariable
|
||||
{
|
||||
Task.Run(async () =>
|
||||
{
|
||||
Nodes = await PopulateBranchAsync(ObjectIds.ObjectsFolder);
|
||||
Nodes = await PopulateBranchAsync(ObjectIds.ObjectsFolder, isShowSubvariable: IsShowSubvariable);
|
||||
overlay = false;
|
||||
await InvokeAsync(StateHasChanged);
|
||||
});
|
||||
@@ -206,10 +211,10 @@ public partial class OPCUAImportVariable
|
||||
private async Task PopulateBranchAsync(OPCUATagModel model)
|
||||
{
|
||||
var sourceId = (NodeId)model.Tag.NodeId;
|
||||
model.Nodes = await PopulateBranchAsync(sourceId);
|
||||
model.Nodes = await PopulateBranchAsync(sourceId, isShowSubvariable: IsShowSubvariable);
|
||||
}
|
||||
|
||||
private async Task<List<OPCUATagModel>> PopulateBranchAsync(NodeId sourceId, bool isAll = false)
|
||||
private async Task<List<OPCUATagModel>> PopulateBranchAsync(NodeId sourceId, bool isAll = false, bool isShowSubvariable = false)
|
||||
{
|
||||
if (!PLC.Connected)
|
||||
{
|
||||
@@ -232,13 +237,13 @@ public partial class OPCUAImportVariable
|
||||
Name = Utils.Format("{0}", target),
|
||||
Tag = target
|
||||
};
|
||||
//if (target.NodeClass != NodeClass.Variable)
|
||||
if (isShowSubvariable || target.NodeClass != NodeClass.Variable)
|
||||
{
|
||||
var data = await GetReferenceDescriptionCollectionAsync((NodeId)target.NodeId);
|
||||
if (data != null && data.Count > 0)
|
||||
{
|
||||
if (isAll)
|
||||
child.Nodes = await PopulateBranchAsync((NodeId)target.NodeId);
|
||||
child.Nodes = await PopulateBranchAsync((NodeId)target.NodeId, isShowSubvariable: IsShowSubvariable);
|
||||
else
|
||||
child.Nodes = new();
|
||||
}
|
||||
@@ -247,10 +252,32 @@ public partial class OPCUAImportVariable
|
||||
child.Nodes = null;
|
||||
}
|
||||
}
|
||||
//else
|
||||
else
|
||||
{
|
||||
child.Nodes = null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
////if (target.NodeClass != NodeClass.Variable) //这个判断注释后会让子节点也是变量的情况下无法加载
|
||||
//{
|
||||
// child.Nodes = null;
|
||||
// var data = await GetReferenceDescriptionCollectionAsync((NodeId)target.NodeId);
|
||||
// if (data != null && data.Count > 0)
|
||||
// {
|
||||
// if (isAll)
|
||||
// child.Nodes = await PopulateBranchAsync((NodeId)target.NodeId);
|
||||
// else
|
||||
// child.Nodes = new();
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// child.Nodes = null;
|
||||
// }
|
||||
//}
|
||||
////else
|
||||
////{
|
||||
//// child.Nodes = null;
|
||||
////}
|
||||
list.Add(child);
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,15 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
global using ThingsGateway.Foundation.Core;
|
||||
global using ThingsGateway.Gateway.Application;
|
||||
global using ThingsGateway.Gateway.Core;
|
325
framework/Plugin/ThingsGateway.Plugin.QuestDB/QuestDB.cs
Normal file
325
framework/Plugin/ThingsGateway.Plugin.QuestDB/QuestDB.cs
Normal file
@@ -0,0 +1,325 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using Furion;
|
||||
|
||||
using Mapster;
|
||||
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
||||
using SqlSugar;
|
||||
|
||||
using System.Collections.Concurrent;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Reflection;
|
||||
|
||||
using ThingsGateway.Foundation.Extension;
|
||||
using ThingsGateway.Foundation.Extension.ConcurrentQueue;
|
||||
using ThingsGateway.Foundation.Extension.String;
|
||||
|
||||
namespace ThingsGateway.Plugin.QuestDB;
|
||||
public class QuestDB : UpLoadBase
|
||||
{
|
||||
private readonly ConcurrentQueue<QuestDBHistoryValue> DeviceVariableRunTimes = new();
|
||||
private readonly QuestDBProperty driverPropertys = new();
|
||||
private readonly QuestDBVariableProperty variablePropertys = new();
|
||||
private TypeAdapterConfig _config;
|
||||
private GlobalDeviceData _globalDeviceData;
|
||||
|
||||
private List<DeviceVariableRunTime> _uploadVariables = new();
|
||||
private TimerTick exTimerTick;
|
||||
public QuestDB()
|
||||
{
|
||||
_config = new TypeAdapterConfig();
|
||||
_config.ForType<DeviceVariableRunTime, HistoryValue>()
|
||||
.Map(dest => dest.Value, (src) => ValueReturn(src))
|
||||
.Map(dest => dest.CollectTime, (src) => src.CollectTime.ToUniversalTime())//注意sqlsugar插入时无时区,直接utc时间
|
||||
.Map(dest => dest.CreateTime, (src) => DateTime.UtcNow);//注意sqlsugar插入时无时区,直接utc时间
|
||||
}
|
||||
private static object ValueReturn(DeviceVariableRunTime src)
|
||||
{
|
||||
if (src.Value?.ToString()?.IsBoolValue() == true)
|
||||
{
|
||||
if (src.Value.ToBoolean())
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return src.Value;
|
||||
}
|
||||
}
|
||||
|
||||
public override Type DriverDebugUIType => null;
|
||||
public override UpDriverPropertyBase DriverPropertys => driverPropertys;
|
||||
public override List<DeviceVariableRunTime> UploadVariables => _uploadVariables;
|
||||
|
||||
public override VariablePropertyBase VariablePropertys => variablePropertys;
|
||||
|
||||
public override Task AfterStopAsync()
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public override async Task BeforStartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
SqlSugarClient db = GetHisDbAsync();
|
||||
db.DbMaintenance.CreateDatabase();
|
||||
db.CodeFirst.InitTables(typeof(QuestDBHistoryValue));
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
public override async Task ExecuteAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
var db = GetHisDbAsync();
|
||||
{
|
||||
if (!driverPropertys.IsInterval)
|
||||
{
|
||||
try
|
||||
{
|
||||
////变化推送
|
||||
var varList = DeviceVariableRunTimes.ToListWithDequeue();
|
||||
if (varList?.Count != 0)
|
||||
{
|
||||
await InserableAsync(db, varList, cancellationToken);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if (exTimerTick.IsTickHappen())
|
||||
{
|
||||
try
|
||||
{
|
||||
var varList = _uploadVariables.ToList().Adapt<List<QuestDBHistoryValue>>(_config);
|
||||
if (varList?.Count != 0)
|
||||
{
|
||||
await InserableAsync(db, varList, cancellationToken);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (driverPropertys.CycleInterval > UploadDeviceThread.CycleInterval + 50)
|
||||
{
|
||||
try
|
||||
{
|
||||
await Task.Delay(driverPropertys.CycleInterval - UploadDeviceThread.CycleInterval, cancellationToken);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public override bool IsConnected() => _uploadVariables?.Count > 0;
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
try
|
||||
{
|
||||
_globalDeviceData?.AllVariables?.ForEach(a => a.VariableValueChange -= VariableValueChange);
|
||||
_uploadVariables = null;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogError(ex);
|
||||
}
|
||||
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
protected override void Init(UploadDeviceRunTime device)
|
||||
{
|
||||
|
||||
_globalDeviceData = App.GetService<GlobalDeviceData>();
|
||||
|
||||
var tags = _globalDeviceData.AllVariables.Where(a => a.VariablePropertys.ContainsKey(device.Id))
|
||||
.Where(b => GetPropertyValue(b, nameof(variablePropertys.Enable)).ToBoolean())
|
||||
.ToList();
|
||||
|
||||
_uploadVariables = tags;
|
||||
|
||||
if (!driverPropertys.IsInterval)
|
||||
{
|
||||
_uploadVariables.ForEach(a =>
|
||||
{
|
||||
a.VariableValueChange += VariableValueChange;
|
||||
});
|
||||
}
|
||||
|
||||
if (_uploadVariables.Count == 0)
|
||||
{
|
||||
LogMessage.LogWarning("插件变量数量为0");
|
||||
}
|
||||
if (driverPropertys.IntervalTime < 1)
|
||||
driverPropertys.IntervalTime = 10;
|
||||
exTimerTick = new(driverPropertys.IntervalTime * 1000);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Aop设置
|
||||
/// </summary>
|
||||
/// <param name="db"></param>
|
||||
private static void AopSetting(SqlSugarClient db)
|
||||
{
|
||||
var config = db.CurrentConnectionConfig;
|
||||
|
||||
// 设置超时时间
|
||||
db.Ado.CommandTimeOut = 30;
|
||||
|
||||
// 打印SQL语句
|
||||
db.Aop.OnLogExecuting = (sql, pars) =>
|
||||
{
|
||||
//如果不是开发环境就打印sql
|
||||
if (App.HostEnvironment.IsDevelopment())
|
||||
{
|
||||
if (sql.StartsWith("SELECT"))
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.Green;
|
||||
}
|
||||
if (sql.StartsWith("UPDATE"))
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.Yellow;
|
||||
}
|
||||
if (sql.StartsWith("INSERT"))
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.Blue;
|
||||
}
|
||||
if (sql.StartsWith("DELETE"))
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.Red;
|
||||
}
|
||||
WriteSqlLog(UtilMethods.GetSqlString(config.DbType, sql, pars));
|
||||
Console.ForegroundColor = ConsoleColor.White;
|
||||
Console.WriteLine();
|
||||
}
|
||||
};
|
||||
//异常
|
||||
db.Aop.OnError = (ex) =>
|
||||
{
|
||||
//如果不是开发环境就打印日志
|
||||
if (App.WebHostEnvironment.IsDevelopment())
|
||||
{
|
||||
if (ex.Parametres == null) return;
|
||||
Console.ForegroundColor = ConsoleColor.Red;
|
||||
var pars = db.Utilities.SerializeObject(((SugarParameter[])ex.Parametres).ToDictionary(it => it.ParameterName, it => it.Value));
|
||||
WriteSqlLogError(UtilMethods.GetSqlString(config.DbType, ex.Sql, (SugarParameter[])ex.Parametres));
|
||||
Console.ForegroundColor = ConsoleColor.White;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
private static void WriteSqlLog(string msg)
|
||||
{
|
||||
Console.WriteLine("【Sql执行时间】:" + DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat());
|
||||
Console.WriteLine("【Sql语句】:" + msg + Environment.NewLine);
|
||||
}
|
||||
|
||||
private static void WriteSqlLogError(string msg)
|
||||
{
|
||||
Console.WriteLine("【Sql执行错误时间】:" + DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat());
|
||||
Console.WriteLine("【Sql语句】:" + msg + Environment.NewLine);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取数据库链接
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private SqlSugarClient GetHisDbAsync()
|
||||
{
|
||||
var configureExternalServices = new ConfigureExternalServices
|
||||
{
|
||||
EntityService = (type, column) => // 修改列可空-1、带?问号 2、String类型若没有Required
|
||||
{
|
||||
if ((type.PropertyType.IsGenericType && type.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
|
||||
|| (type.PropertyType == typeof(string) && type.GetCustomAttribute<RequiredAttribute>() == null))
|
||||
column.IsNullable = true;
|
||||
},
|
||||
};
|
||||
var sqlSugarClient = new SqlSugarClient(new ConnectionConfig()
|
||||
{
|
||||
ConnectionString = driverPropertys.ConnectStr,//连接字符串
|
||||
DbType = DbType.QuestDB,//数据库类型
|
||||
IsAutoCloseConnection = true, //不设成true要手动close
|
||||
ConfigureExternalServices = configureExternalServices,
|
||||
}
|
||||
);
|
||||
AopSetting(sqlSugarClient);//aop配置
|
||||
return sqlSugarClient;
|
||||
}
|
||||
|
||||
private async Task InserableAsync(SqlSugarClient db, List<QuestDBHistoryValue> dbInserts, CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = await db.Insertable(dbInserts).ExecuteCommandAsync(cancellationToken);
|
||||
if (result > 0)
|
||||
LogMessage.Trace(FoundationConst.LogMessageHeader + dbInserts.ToJsonString());
|
||||
//连接成功时补发缓存数据
|
||||
var cacheData = await CacheDb.GetCacheData();
|
||||
foreach (var item in cacheData)
|
||||
{
|
||||
try
|
||||
{
|
||||
var data = item.CacheStr.FromJsonString<List<QuestDBHistoryValue>>();
|
||||
var cacheresult = await db.Insertable(data).ExecuteCommandAsync(cancellationToken);
|
||||
if (cacheresult > 0)
|
||||
{
|
||||
await CacheDb.DeleteCacheData(item.Id);
|
||||
LogMessage.Trace(FoundationConst.LogMessageHeader + $"主题:{item.Topic}{Environment.NewLine}负载:{item.CacheStr}");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage.LogWarning(ex);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage.LogWarning(ex);
|
||||
await CacheDb.AddCacheData("", dbInserts.ToJsonString(), driverPropertys.CacheMaxCount);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void VariableValueChange(DeviceVariableRunTime collectVariableRunTime)
|
||||
{
|
||||
if (!driverPropertys.IsInterval)
|
||||
DeviceVariableRunTimes.Enqueue(collectVariableRunTime.Adapt<QuestDBHistoryValue>(_config));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@@ -0,0 +1,62 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using SqlSugar;
|
||||
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace ThingsGateway.Gateway.Core;
|
||||
/// <summary>
|
||||
/// 历史数据表
|
||||
/// </summary>
|
||||
[SugarTable("historyValue", TableDescription = "历史数据表")]
|
||||
public class QuestDBHistoryValue
|
||||
{
|
||||
/// <summary>
|
||||
/// 采集时间
|
||||
/// </summary>
|
||||
[TimeDbSplitField(DateType.Month)]
|
||||
[Description("采集时间")]
|
||||
public DateTime CollectTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 上传时间
|
||||
/// </summary>
|
||||
[Description("上传时间")]
|
||||
public DateTime CreateTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 设备名称
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDataType = "symbol")]
|
||||
[Description("设备名称")]
|
||||
public string DeviceName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 变量名称
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDataType = "symbol")]
|
||||
[Description("变量名称")]
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否在线
|
||||
/// </summary>
|
||||
[Description("是否在线")]
|
||||
public bool IsOnline { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 变量值
|
||||
/// </summary>
|
||||
[Description("变量值")]
|
||||
public double Value { get; set; }
|
||||
}
|
@@ -0,0 +1,31 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace ThingsGateway.Plugin.QuestDB;
|
||||
|
||||
public class QuestDBProperty : UpDriverPropertyBase
|
||||
{
|
||||
[DeviceProperty("链接字符串", "")] public string ConnectStr { get; set; } = "host=localhost;port=8812;username=admin;password=quest;database=qdb;ServerCompatibilityMode=NoTypeLoading;";
|
||||
[DeviceProperty("是否间隔插入", "False时将每次变化写入")] public bool IsInterval { get; set; } = true;
|
||||
[DeviceProperty("间隔时间", "秒,实时表时代表更新间隔,历史表时代表插入间隔")] public int IntervalTime { get; set; } = 10;
|
||||
[DeviceProperty("缓存最大条数", "默认2千条")] public int CacheMaxCount { get; set; } = 2000;
|
||||
|
||||
/// <summary>
|
||||
/// 线程循环间隔
|
||||
/// </summary>
|
||||
[DeviceProperty("线程循环间隔", "最小10ms")]
|
||||
public int CycleInterval { get; set; } = 1000;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@@ -0,0 +1,22 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace ThingsGateway.Plugin.QuestDB;
|
||||
|
||||
public class QuestDBVariableProperty : VariablePropertyBase
|
||||
{
|
||||
[VariableProperty("启用", "")]
|
||||
public bool Enable { get; set; } = true;
|
||||
}
|
||||
|
||||
|
||||
|
@@ -0,0 +1,14 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
|
||||
|
||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
||||
|
||||
<Exec Command=" set dir="$(SolutionDir)Web\ThingsGateway.Web.Entry\bin\$(Configuration)\$(TargetFramework)\Plugins\$(AssemblyName)"
 if not exist %25dir%25 md %25dir%25 
copy "$(TargetDir)*QuestDB*.dll" %25dir%25



" />
|
||||
|
||||
</Target>
|
||||
|
||||
|
||||
|
||||
|
||||
</Project>
|
@@ -93,7 +93,7 @@ public class RabbitMQClient : UpLoadBase
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex, ToString());
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,7 +124,7 @@ public class RabbitMQClient : UpLoadBase
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex, ToString());
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -150,7 +150,7 @@ public class RabbitMQClient : UpLoadBase
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex, ToString());
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,7 +188,7 @@ public class RabbitMQClient : UpLoadBase
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex, ToString());
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -214,7 +214,7 @@ public class RabbitMQClient : UpLoadBase
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex, ToString());
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -224,7 +224,7 @@ public class RabbitMQClient : UpLoadBase
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex, ToString());
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
|
||||
|
||||
@@ -233,7 +233,7 @@ public class RabbitMQClient : UpLoadBase
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex, ToString());
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
try
|
||||
{
|
||||
@@ -257,7 +257,7 @@ public class RabbitMQClient : UpLoadBase
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex, ToString());
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -275,7 +275,7 @@ public class RabbitMQClient : UpLoadBase
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex, ToString());
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -305,7 +305,7 @@ public class RabbitMQClient : UpLoadBase
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex, ToString());
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -323,7 +323,7 @@ public class RabbitMQClient : UpLoadBase
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex, ToString());
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -338,7 +338,7 @@ public class RabbitMQClient : UpLoadBase
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex, ToString());
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
|
||||
if (driverPropertys.CycleInterval > UploadDeviceThread.CycleInterval + 50)
|
||||
@@ -482,7 +482,7 @@ public class RabbitMQClient : UpLoadBase
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex, ToString());
|
||||
LogMessage?.LogWarning(ex);
|
||||
await CacheDb.AddCacheData(queueName, data, driverPropertys.CacheMaxCount);
|
||||
}
|
||||
|
||||
|
15
framework/Plugin/ThingsGateway.Plugin.SQLDB/GlobalUsings.cs
Normal file
15
framework/Plugin/ThingsGateway.Plugin.SQLDB/GlobalUsings.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
global using ThingsGateway.Foundation.Core;
|
||||
global using ThingsGateway.Gateway.Application;
|
||||
global using ThingsGateway.Gateway.Core;
|
334
framework/Plugin/ThingsGateway.Plugin.SQLDB/SQLDB.cs
Normal file
334
framework/Plugin/ThingsGateway.Plugin.SQLDB/SQLDB.cs
Normal file
@@ -0,0 +1,334 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using Furion;
|
||||
|
||||
using Mapster;
|
||||
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
||||
using SqlSugar;
|
||||
|
||||
using System.Collections.Concurrent;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Reflection;
|
||||
|
||||
using ThingsGateway.Foundation.Extension.ConcurrentQueue;
|
||||
using ThingsGateway.Foundation.Extension.String;
|
||||
|
||||
using Yitter.IdGenerator;
|
||||
|
||||
namespace ThingsGateway.Plugin.SQLDB;
|
||||
public class SQLDB : UpLoadBase
|
||||
{
|
||||
private readonly ConcurrentQueue<SQLHistoryValue> DeviceVariableRunTimes = new();
|
||||
private readonly SQLDBProperty driverPropertys = new();
|
||||
private readonly SQLDBVariableProperty variablePropertys = new();
|
||||
private TypeAdapterConfig _config;
|
||||
private GlobalDeviceData _globalDeviceData;
|
||||
|
||||
private List<DeviceVariableRunTime> _uploadVariables = new();
|
||||
private TimerTick exTimerTick;
|
||||
private TimerTick exRealTimerTick;
|
||||
public SQLDB()
|
||||
{
|
||||
_config = new TypeAdapterConfig();
|
||||
_config.ForType<DeviceVariableRunTime, SQLHistoryValue>()
|
||||
.Map(dest => dest.Id, (src) => YitIdHelper.NextId())
|
||||
.Map(dest => dest.CreateTime, (src) => DateTime.Now);
|
||||
}
|
||||
|
||||
public override Type DriverDebugUIType => null;
|
||||
public override UpDriverPropertyBase DriverPropertys => driverPropertys;
|
||||
public override List<DeviceVariableRunTime> UploadVariables => _uploadVariables;
|
||||
|
||||
public override VariablePropertyBase VariablePropertys => variablePropertys;
|
||||
|
||||
public override Task AfterStopAsync()
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public override async Task BeforStartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
var db = GetHisDbAsync();
|
||||
db.CodeFirst.InitTables(typeof(SQLHistoryValue));
|
||||
db.MappingTables.Add("SQLRealValue", driverPropertys.ReadDBTableName); // typeof(类).Name 可以拿到类名
|
||||
db.CodeFirst.InitTables(typeof(SQLRealValue)); //生成的表名是 newTableName
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
public override async Task ExecuteAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
var db = GetHisDbAsync();
|
||||
|
||||
if (driverPropertys.IsReadDB)
|
||||
{
|
||||
if (exRealTimerTick.IsTickHappen())
|
||||
{
|
||||
try
|
||||
{
|
||||
var varList = _uploadVariables.ToList().Adapt<List<SQLRealValue>>();
|
||||
if (varList?.Count != 0)
|
||||
{
|
||||
//var result = await db.Storageable(varList).As(driverPropertys.ReadDBTableName).ExecuteCommandAsync(cancellationToken);
|
||||
await db.Fastest<SQLRealValue>().AS(driverPropertys.ReadDBTableName).PageSize(100000).BulkUpdateAsync(varList);
|
||||
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
if (!driverPropertys.IsInterval)
|
||||
{
|
||||
try
|
||||
{
|
||||
////变化推送
|
||||
var varList = DeviceVariableRunTimes.ToListWithDequeue();
|
||||
if (varList?.Count != 0)
|
||||
{
|
||||
await InserableAsync(db, varList, cancellationToken);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if (exTimerTick.IsTickHappen())
|
||||
{
|
||||
try
|
||||
{
|
||||
var varList = _uploadVariables.ToList().Adapt<List<SQLHistoryValue>>(_config);
|
||||
if (varList?.Count != 0)
|
||||
{
|
||||
await InserableAsync(db, varList, cancellationToken);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (driverPropertys.CycleInterval > UploadDeviceThread.CycleInterval + 50)
|
||||
{
|
||||
try
|
||||
{
|
||||
await Task.Delay(driverPropertys.CycleInterval - UploadDeviceThread.CycleInterval, cancellationToken);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取数据库链接
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public SqlSugarClient GetHisDbAsync()
|
||||
{
|
||||
var configureExternalServices = new ConfigureExternalServices
|
||||
{
|
||||
EntityService = (type, column) => // 修改列可空-1、带?问号 2、String类型若没有Required
|
||||
{
|
||||
if ((type.PropertyType.IsGenericType && type.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
|
||||
|| (type.PropertyType == typeof(string) && type.GetCustomAttribute<RequiredAttribute>() == null))
|
||||
column.IsNullable = true;
|
||||
},
|
||||
};
|
||||
var sqlSugarClient = new SqlSugarClient(new ConnectionConfig()
|
||||
{
|
||||
ConnectionString = driverPropertys.ConnectStr,//连接字符串
|
||||
DbType = driverPropertys.DbType,//数据库类型
|
||||
IsAutoCloseConnection = true, //不设成true要手动close
|
||||
ConfigureExternalServices = configureExternalServices,
|
||||
}
|
||||
);
|
||||
AopSetting(sqlSugarClient);//aop配置
|
||||
return sqlSugarClient;
|
||||
}
|
||||
|
||||
public override bool IsConnected() => _uploadVariables?.Count > 0;
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
try
|
||||
{
|
||||
_globalDeviceData?.AllVariables?.ForEach(a => a.VariableValueChange -= VariableValueChange);
|
||||
_uploadVariables = null;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogError(ex);
|
||||
}
|
||||
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
protected override void Init(UploadDeviceRunTime device)
|
||||
{
|
||||
|
||||
_globalDeviceData = App.GetService<GlobalDeviceData>();
|
||||
|
||||
var tags = _globalDeviceData.AllVariables.Where(a => a.VariablePropertys.ContainsKey(device.Id))
|
||||
.Where(b => GetPropertyValue(b, nameof(variablePropertys.Enable)).ToBoolean())
|
||||
.ToList();
|
||||
|
||||
_uploadVariables = tags;
|
||||
|
||||
if (!driverPropertys.IsReadDB)
|
||||
if (!driverPropertys.IsInterval)
|
||||
{
|
||||
_uploadVariables.ForEach(a =>
|
||||
{
|
||||
a.VariableValueChange += VariableValueChange;
|
||||
});
|
||||
}
|
||||
|
||||
if (_uploadVariables.Count == 0)
|
||||
{
|
||||
LogMessage.LogWarning("插件变量数量为0");
|
||||
}
|
||||
if (driverPropertys.IntervalTime < 1)
|
||||
driverPropertys.IntervalTime = 10;
|
||||
exTimerTick = new(driverPropertys.IntervalTime * 1000);
|
||||
exRealTimerTick = new(driverPropertys.IntervalTime * 1000);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Aop设置
|
||||
/// </summary>
|
||||
/// <param name="db"></param>
|
||||
private static void AopSetting(SqlSugarClient db)
|
||||
{
|
||||
var config = db.CurrentConnectionConfig;
|
||||
|
||||
// 设置超时时间
|
||||
db.Ado.CommandTimeOut = 30;
|
||||
|
||||
// 打印SQL语句
|
||||
db.Aop.OnLogExecuting = (sql, pars) =>
|
||||
{
|
||||
//如果不是开发环境就打印sql
|
||||
if (App.HostEnvironment.IsDevelopment())
|
||||
{
|
||||
if (sql.StartsWith("SELECT"))
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.Green;
|
||||
}
|
||||
if (sql.StartsWith("UPDATE"))
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.Yellow;
|
||||
}
|
||||
if (sql.StartsWith("INSERT"))
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.Blue;
|
||||
}
|
||||
if (sql.StartsWith("DELETE"))
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.Red;
|
||||
}
|
||||
WriteSqlLog(UtilMethods.GetSqlString(config.DbType, sql, pars));
|
||||
Console.ForegroundColor = ConsoleColor.White;
|
||||
Console.WriteLine();
|
||||
}
|
||||
};
|
||||
//异常
|
||||
db.Aop.OnError = (ex) =>
|
||||
{
|
||||
//如果不是开发环境就打印日志
|
||||
if (App.WebHostEnvironment.IsDevelopment())
|
||||
{
|
||||
if (ex.Parametres == null) return;
|
||||
Console.ForegroundColor = ConsoleColor.Red;
|
||||
var pars = db.Utilities.SerializeObject(((SugarParameter[])ex.Parametres).ToDictionary(it => it.ParameterName, it => it.Value));
|
||||
WriteSqlLogError(UtilMethods.GetSqlString(config.DbType, ex.Sql, (SugarParameter[])ex.Parametres));
|
||||
Console.ForegroundColor = ConsoleColor.White;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
private static void WriteSqlLog(string msg)
|
||||
{
|
||||
Console.WriteLine("【Sql执行时间】:" + DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat());
|
||||
Console.WriteLine("【Sql语句】:" + msg + Environment.NewLine);
|
||||
}
|
||||
private static void WriteSqlLogError(string msg)
|
||||
{
|
||||
Console.WriteLine("【Sql执行错误时间】:" + DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat());
|
||||
Console.WriteLine("【Sql语句】:" + msg + Environment.NewLine);
|
||||
}
|
||||
private async Task InserableAsync(SqlSugarClient db, List<SQLHistoryValue> dbInserts, CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = await db.Insertable(dbInserts).SplitTable().ExecuteCommandAsync();
|
||||
if (result > 0)
|
||||
LogMessage.Trace(FoundationConst.LogMessageHeader + dbInserts.ToJsonString());
|
||||
//连接成功时补发缓存数据
|
||||
var cacheData = await CacheDb.GetCacheData();
|
||||
foreach (var item in cacheData)
|
||||
{
|
||||
try
|
||||
{
|
||||
var data = item.CacheStr.FromJsonString<List<SQLHistoryValue>>();
|
||||
var cacheresult = await db.Insertable(data).SplitTable().ExecuteCommandAsync();
|
||||
if (cacheresult > 0)
|
||||
{
|
||||
await CacheDb.DeleteCacheData(item.Id);
|
||||
LogMessage.Trace(FoundationConst.LogMessageHeader + $"主题:{item.Topic}{Environment.NewLine}负载:{item.CacheStr}");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage.LogWarning(ex);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage.LogWarning(ex);
|
||||
await CacheDb.AddCacheData("", dbInserts.ToJsonString(), driverPropertys.CacheMaxCount);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void VariableValueChange(DeviceVariableRunTime collectVariableRunTime)
|
||||
{
|
||||
if (!driverPropertys.IsReadDB)
|
||||
if (!driverPropertys.IsInterval)
|
||||
DeviceVariableRunTimes.Enqueue(collectVariableRunTime.Adapt<SQLHistoryValue>(_config));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
37
framework/Plugin/ThingsGateway.Plugin.SQLDB/SQLDBProperty.cs
Normal file
37
framework/Plugin/ThingsGateway.Plugin.SQLDB/SQLDBProperty.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using SqlSugar;
|
||||
|
||||
namespace ThingsGateway.Plugin.SQLDB;
|
||||
|
||||
public class SQLDBProperty : UpDriverPropertyBase
|
||||
{
|
||||
[DeviceProperty("是否实时表", "true=>实时表更新,false=>历史存储(按月分表)")] public bool IsReadDB { get; set; } = false;
|
||||
[DeviceProperty("实时表名称", "")] public string ReadDBTableName { get; set; } = "ReadDBTableName";
|
||||
|
||||
[DeviceProperty("数据库类型", "MySql/SqlServer")] public DbType DbType { get; set; } = DbType.MySql;
|
||||
[DeviceProperty("链接字符串", "")] public string ConnectStr { get; set; } = "server=localhost;Database=test;Uid=root;Pwd=111111;AllowLoadLocalInfile=true;";
|
||||
[DeviceProperty("是否间隔插入", "False时将每次变化写入")] public bool IsInterval { get; set; } = true;
|
||||
[DeviceProperty("间隔时间", "秒,实时表时代表更新间隔,历史表时代表插入间隔")] public int IntervalTime { get; set; } = 10;
|
||||
[DeviceProperty("缓存最大条数", "默认2千条")] public int CacheMaxCount { get; set; } = 2000;
|
||||
|
||||
/// <summary>
|
||||
/// 线程循环间隔
|
||||
/// </summary>
|
||||
[DeviceProperty("线程循环间隔", "最小10ms")]
|
||||
public int CycleInterval { get; set; } = 1000;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@@ -0,0 +1,22 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace ThingsGateway.Plugin.SQLDB;
|
||||
|
||||
public class SQLDBVariableProperty : VariablePropertyBase
|
||||
{
|
||||
[VariableProperty("启用", "")]
|
||||
public bool Enable { get; set; } = true;
|
||||
}
|
||||
|
||||
|
||||
|
@@ -0,0 +1,56 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using SqlSugar;
|
||||
|
||||
namespace ThingsGateway.Plugin.SQLDB;
|
||||
|
||||
[SplitTable(SplitType.Month)]//按月分表 (自带分表支持 年、季、月、周、日)
|
||||
[SugarTable("historyValue_{year}{month}{day}", TableDescription = "设备采集历史表")]//3个变量必须要有
|
||||
[SugarIndex("index_Name", nameof(SQLHistoryValue.Name), OrderByType.Desc)]
|
||||
[SugarIndex("index_DeviceName", nameof(SQLHistoryValue.DeviceName), OrderByType.Desc)]
|
||||
[SugarIndex("index_CollectTime", nameof(SQLHistoryValue.CollectTime), OrderByType.Desc)]
|
||||
public class SQLHistoryValue
|
||||
{
|
||||
[SugarColumn(ColumnDescription = "Id", IsPrimaryKey = true)]
|
||||
public long Id { get; set; }
|
||||
/// <summary>
|
||||
/// 变量名称
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnName = "Name", ColumnDescription = "变量名称")]
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 设备名称
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnName = "DeviceName", ColumnDescription = "设备名称")]
|
||||
public string DeviceName { get; set; }
|
||||
|
||||
///<summary>
|
||||
///实时值
|
||||
///</summary>
|
||||
[SugarColumn(ColumnName = "Value", ColumnDescription = "实时值")]
|
||||
public string Value { get; set; }
|
||||
|
||||
///<summary>
|
||||
///是否在线
|
||||
///</summary>
|
||||
[SugarColumn(ColumnName = "IsOnline", ColumnDescription = "是否在线 True=在线;False=离线")]
|
||||
public bool IsOnline { get; set; }
|
||||
|
||||
|
||||
public DateTime CollectTime { get; set; }
|
||||
|
||||
[SplitField] //分表字段 在插入的时候会根据这个字段插入哪个表,在更新删除的时候用这个字段找出相关表
|
||||
public DateTime CreateTime { get; set; }
|
||||
}
|
||||
|
52
framework/Plugin/ThingsGateway.Plugin.SQLDB/SQLRealValue.cs
Normal file
52
framework/Plugin/ThingsGateway.Plugin.SQLDB/SQLRealValue.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using SqlSugar;
|
||||
|
||||
namespace ThingsGateway.Plugin.SQLDB;
|
||||
|
||||
[SugarTable(TableDescription = "设备采集实时表")]
|
||||
[SugarIndex("index_Name", nameof(SQLHistoryValue.Name), OrderByType.Desc)]
|
||||
[SugarIndex("index_DeviceName", nameof(SQLHistoryValue.DeviceName), OrderByType.Desc)]
|
||||
[SugarIndex("index_CollectTime", nameof(SQLHistoryValue.CollectTime), OrderByType.Desc)]
|
||||
public class SQLRealValue
|
||||
{
|
||||
[SugarColumn(ColumnDescription = "Id", IsPrimaryKey = true)]
|
||||
public long Id { get; set; }
|
||||
/// <summary>
|
||||
/// 变量名称
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnName = "Name", ColumnDescription = "变量名称")]
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 设备名称
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnName = "DeviceName", ColumnDescription = "设备名称")]
|
||||
public string DeviceName { get; set; }
|
||||
|
||||
///<summary>
|
||||
///实时值
|
||||
///</summary>
|
||||
[SugarColumn(ColumnName = "Value", ColumnDescription = "实时值")]
|
||||
public string Value { get; set; }
|
||||
|
||||
///<summary>
|
||||
///是否在线
|
||||
///</summary>
|
||||
[SugarColumn(ColumnName = "IsOnline", ColumnDescription = "是否在线 True=在线;False=离线")]
|
||||
public bool IsOnline { get; set; }
|
||||
|
||||
public DateTime CollectTime { get; set; }
|
||||
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user