Compare commits

..

37 Commits

Author SHA1 Message Date
Kimdiego2098
a64ab7df4e 更新版本号 2023-11-24 14:48:53 +08:00
Kimdiego2098
82cd64cb50 10功能码写入时 修改需判断的crc长度 2023-11-24 14:48:28 +08:00
Kimdiego2098
065bfb8694 修复 modbusTcpDtu 初始化 空指针错误 2023-11-24 09:44:47 +08:00
Kimdiego2098
6db335cf87 OPCUA插件afterStop方法重写时需执行父类方法 2023-11-23 20:51:08 +08:00
Kimdiego2098
155f4670e9 调整网关状态页面 2023-11-23 20:49:35 +08:00
Kimdiego2098
50522b571a 修改内存缓存mapster选项 2023-11-23 15:22:39 +08:00
Kimdiego2098
8e138863ce 添加kafka的SecurityProtocol与SaslMechanism参数说明 2023-11-22 21:29:08 +08:00
Kimdiego2098
7d8dfe628d 修复上个提交导致的excel导入产生空指针错误 2023-11-22 20:52:58 +08:00
Kimdiego2098
8baed5b306 excel导入导出设备表时,去除多余的字段 2023-11-22 16:09:41 +08:00
Kimdiego2098
41a5ffd214 socktClient重载toString 2023-11-22 15:28:04 +08:00
Kimdiego2098
c6aec3a1af 更新版本号 2023-11-22 14:06:52 +08:00
Kimdiego2098
22e30f7a62 代码文件编码更改 2023-11-22 14:02:41 +08:00
Kimdiego2098
57711b8ab5 修复变量上传属性在编辑页面不显示的问题 2023-11-22 13:35:44 +08:00
Kimdiego2098
90ff1259ea 修复变量上传属性在编辑页面不显示的问题 2023-11-22 13:30:42 +08:00
Kimdiego2098
d88fc5ccd7 去除不存在的菜单 2023-11-21 18:19:14 +08:00
Kimdiego2098
5aaca2aa9c 调整循环延时时间限值 2023-11-21 16:27:11 +08:00
Kimdiego2098
8b9ca56e17 调试mqtt依赖 2023-11-21 15:07:07 +08:00
Kimdiego2098
e4f3772e6d 去除上传间隔1s限制 2023-11-21 11:46:33 +08:00
Kimdiego2098
d58ec81d20 整理代码 2023-11-21 11:41:44 +08:00
Kimdiego2098
415aae44b6 更新依赖 2023-11-21 08:44:47 +08:00
Kimdiego2098
a533286658 更新版本号 2023-11-20 23:05:12 +08:00
Kimdiego2098
e59f91cd82 去除treeview 2023-11-20 23:04:54 +08:00
Kimdiego2098
5f8b85d8a4 去除treeview显示 2023-11-20 22:53:34 +08:00
Kimdiego2098
47c7b88436 更新版本号 2023-11-20 22:47:18 +08:00
Kimdiego2098
90006782f2 mqttserver/client插件支持websocket通道,直接对接前端 2023-11-20 22:42:08 +08:00
Kimdiego2098
c3d49cbe70 mqttserver/client插件支持websocket通道,直接对接前端 2023-11-20 22:33:26 +08:00
Kimdiego2098
112323a360 modbusTcpServer最大连接数设为3w 2023-11-20 19:46:07 +08:00
Kimdiego2098
9d08c90fda 更新依赖 2023-11-20 17:35:42 +08:00
Kimdiego2098
602d24deec 添加admin-解决方案 2023-11-20 15:38:33 +08:00
Kimdiego2098
a2b9f66785 修复设备curd服务aop失效的问题 2023-11-19 23:30:11 +08:00
Kimdiego2098
7cbf289b50 更新版本号 2023-11-19 22:32:53 +08:00
Kimdiego2098
4097da79a5 modbus server 添加是否立即写入内存的选项 2023-11-19 22:32:13 +08:00
Kimdiego2098
91b7ae554f 默认开启多标签 2023-11-19 22:31:47 +08:00
Kimdiego2098
3121aa2542 添加历史报警插件 2023-11-19 22:19:05 +08:00
Kimdiego2098
4bf895e6e1 修复4.0代码 s7协议未设置适配器导致初始化/读写失败的问题 2023-11-19 21:49:32 +08:00
Kimdiego2098
0c5489e920 增加上传插件 缓存基类 2023-11-19 15:20:01 +08:00
Kimdiego2098
d63c3aaa80 获取插件继承属性时,去除不重写特性的属性 2023-11-19 14:15:58 +08:00
101 changed files with 1440 additions and 632 deletions

View File

@@ -0,0 +1,101 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.6.33927.249
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "admin", "admin", "{4E66C22C-0636-4949-BF6A-9E3BBE1550BA}"
ProjectSection(SolutionItems) = preProject
admin\Directory.Build.props = admin\Directory.Build.props
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Components", "admin\ThingsGateway.Components\ThingsGateway.Components.csproj", "{0A891D8E-23B3-46AD-8D30-565EE5004F93}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Core", "admin\ThingsGateway.Core\ThingsGateway.Core.csproj", "{A712EAEE-94F2-4F01-8C1C-2EC802280DD7}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Admin.Core", "admin\ThingsGateway.Admin.Core\ThingsGateway.Admin.Core.csproj", "{5DA3D2BD-6768-4479-B52F-49E022EFF310}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Admin.Blazor", "admin\ThingsGateway.Admin.Blazor\ThingsGateway.Admin.Blazor.csproj", "{8DD5DF98-7FDE-4B49-8661-AEB44D923CFE}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Admin.Application", "admin\ThingsGateway.Admin.Application\ThingsGateway.Admin.Application.csproj", "{D6685A42-2712-417A-92C5-5EFF90B9FA94}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Admin.ApiController", "admin\ThingsGateway.Admin.ApiController\ThingsGateway.Admin.ApiController.csproj", "{0D17D801-6DAA-4FD1-9A99-F9F07FA6BA88}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "web", "web", "{F0C9A8CB-231B-45E0-B91B-4FEF7EF47197}"
ProjectSection(SolutionItems) = preProject
web\Directory.Build.props = web\Directory.Build.props
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Web.Core", "web\ThingsGateway.Web.Core\ThingsGateway.Web.Core.csproj", "{D37EC028-EA46-4510-8261-6E780A906314}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Web.Entry", "web\ThingsGateway.Web.Entry\ThingsGateway.Web.Entry.csproj", "{C5F662EB-991F-438D-BF61-EF87E7371C04}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "解决方案项", "解决方案项", "{97B23D8B-C6C0-4746-A21F-C7B49354B284}"
ProjectSection(SolutionItems) = preProject
..\.gitignore = ..\.gitignore
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Foundation", "foundation\ThingsGateway.Foundation\ThingsGateway.Foundation.csproj", "{6961511A-8787-42AF-827D-B630B2AF4791}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "foundation", "foundation", "{268A1A81-2685-47E1-9986-5934A58A31A4}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{0A891D8E-23B3-46AD-8D30-565EE5004F93}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0A891D8E-23B3-46AD-8D30-565EE5004F93}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0A891D8E-23B3-46AD-8D30-565EE5004F93}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0A891D8E-23B3-46AD-8D30-565EE5004F93}.Release|Any CPU.Build.0 = Release|Any CPU
{A712EAEE-94F2-4F01-8C1C-2EC802280DD7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A712EAEE-94F2-4F01-8C1C-2EC802280DD7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A712EAEE-94F2-4F01-8C1C-2EC802280DD7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A712EAEE-94F2-4F01-8C1C-2EC802280DD7}.Release|Any CPU.Build.0 = Release|Any CPU
{5DA3D2BD-6768-4479-B52F-49E022EFF310}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5DA3D2BD-6768-4479-B52F-49E022EFF310}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5DA3D2BD-6768-4479-B52F-49E022EFF310}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5DA3D2BD-6768-4479-B52F-49E022EFF310}.Release|Any CPU.Build.0 = Release|Any CPU
{8DD5DF98-7FDE-4B49-8661-AEB44D923CFE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8DD5DF98-7FDE-4B49-8661-AEB44D923CFE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8DD5DF98-7FDE-4B49-8661-AEB44D923CFE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8DD5DF98-7FDE-4B49-8661-AEB44D923CFE}.Release|Any CPU.Build.0 = Release|Any CPU
{D6685A42-2712-417A-92C5-5EFF90B9FA94}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D6685A42-2712-417A-92C5-5EFF90B9FA94}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D6685A42-2712-417A-92C5-5EFF90B9FA94}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D6685A42-2712-417A-92C5-5EFF90B9FA94}.Release|Any CPU.Build.0 = Release|Any CPU
{0D17D801-6DAA-4FD1-9A99-F9F07FA6BA88}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0D17D801-6DAA-4FD1-9A99-F9F07FA6BA88}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0D17D801-6DAA-4FD1-9A99-F9F07FA6BA88}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0D17D801-6DAA-4FD1-9A99-F9F07FA6BA88}.Release|Any CPU.Build.0 = Release|Any CPU
{D37EC028-EA46-4510-8261-6E780A906314}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D37EC028-EA46-4510-8261-6E780A906314}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D37EC028-EA46-4510-8261-6E780A906314}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D37EC028-EA46-4510-8261-6E780A906314}.Release|Any CPU.Build.0 = Release|Any CPU
{C5F662EB-991F-438D-BF61-EF87E7371C04}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C5F662EB-991F-438D-BF61-EF87E7371C04}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C5F662EB-991F-438D-BF61-EF87E7371C04}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C5F662EB-991F-438D-BF61-EF87E7371C04}.Release|Any CPU.Build.0 = Release|Any CPU
{6961511A-8787-42AF-827D-B630B2AF4791}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6961511A-8787-42AF-827D-B630B2AF4791}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6961511A-8787-42AF-827D-B630B2AF4791}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6961511A-8787-42AF-827D-B630B2AF4791}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{0A891D8E-23B3-46AD-8D30-565EE5004F93} = {4E66C22C-0636-4949-BF6A-9E3BBE1550BA}
{A712EAEE-94F2-4F01-8C1C-2EC802280DD7} = {4E66C22C-0636-4949-BF6A-9E3BBE1550BA}
{5DA3D2BD-6768-4479-B52F-49E022EFF310} = {4E66C22C-0636-4949-BF6A-9E3BBE1550BA}
{8DD5DF98-7FDE-4B49-8661-AEB44D923CFE} = {4E66C22C-0636-4949-BF6A-9E3BBE1550BA}
{D6685A42-2712-417A-92C5-5EFF90B9FA94} = {4E66C22C-0636-4949-BF6A-9E3BBE1550BA}
{0D17D801-6DAA-4FD1-9A99-F9F07FA6BA88} = {4E66C22C-0636-4949-BF6A-9E3BBE1550BA}
{D37EC028-EA46-4510-8261-6E780A906314} = {F0C9A8CB-231B-45E0-B91B-4FEF7EF47197}
{C5F662EB-991F-438D-BF61-EF87E7371C04} = {F0C9A8CB-231B-45E0-B91B-4FEF7EF47197}
{6961511A-8787-42AF-827D-B630B2AF4791} = {268A1A81-2685-47E1-9986-5934A58A31A4}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {C49B2D3E-6818-4E28-91B7-6E4E7E264BBB}
EndGlobalSection
EndGlobal

View File

@@ -82,6 +82,7 @@ EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "解决方案项", "解决方案项", "{97B23D8B-C6C0-4746-A21F-C7B49354B284}"
ProjectSection(SolutionItems) = preProject
..\.gitignore = ..\.gitignore
..\README.md = ..\README.md
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Plugin.Kafka", "plugin\ThingsGateway.Plugin.Kafka\ThingsGateway.Plugin.Kafka.csproj", "{E4B8B8E6-FAE7-43BA-9A51-33A3CD9FB825}"
@@ -102,6 +103,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Plugin.OPCDA"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Plugin.OPCUA", "plugin\ThingsGateway.Plugin.OPCUA\ThingsGateway.Plugin.OPCUA.csproj", "{FD4969DB-3CCE-4CCF-BAE4-1BE8A3F40812}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Plugin.SQLHisAlarm", "plugin\ThingsGateway.Plugin.SQLHisAlarm\ThingsGateway.Plugin.SQLHisAlarm.csproj", "{0947E6C0-6371-4483-B0ED-191FB5073151}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -236,6 +239,10 @@ Global
{FD4969DB-3CCE-4CCF-BAE4-1BE8A3F40812}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FD4969DB-3CCE-4CCF-BAE4-1BE8A3F40812}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FD4969DB-3CCE-4CCF-BAE4-1BE8A3F40812}.Release|Any CPU.Build.0 = Release|Any CPU
{0947E6C0-6371-4483-B0ED-191FB5073151}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0947E6C0-6371-4483-B0ED-191FB5073151}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0947E6C0-6371-4483-B0ED-191FB5073151}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0947E6C0-6371-4483-B0ED-191FB5073151}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -273,6 +280,7 @@ Global
{AC4295F2-AB2F-4137-99EF-80FA5C83896B} = {E65490B8-D2E2-4693-B39C-15703B1EBFBB}
{9DA9AED3-9572-4378-A2A6-4D792D67ADDC} = {E65490B8-D2E2-4693-B39C-15703B1EBFBB}
{FD4969DB-3CCE-4CCF-BAE4-1BE8A3F40812} = {E65490B8-D2E2-4693-B39C-15703B1EBFBB}
{0947E6C0-6371-4483-B0ED-191FB5073151} = {E65490B8-D2E2-4693-B39C-15703B1EBFBB}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {C49B2D3E-6818-4E28-91B7-6E4E7E264BBB}

View File

@@ -2,7 +2,7 @@
<PropertyGroup>
<ImplicitUsings>enable</ImplicitUsings>
<TargetFrameworks>net6.0;net8.0;</TargetFrameworks>
<Version>4.0.0.0</Version>
<Version>4.0.0.5</Version>
<LangVersion>latest</LangVersion>
<ImplicitUsings>enable</ImplicitUsings>
<Authors>Diego</Authors>

View File

@@ -86,7 +86,7 @@ public class SysConfigSeedData : ISqlSugarEntitySeedData<SysConfig>
Id = 22222222222229,
Category = ConfigConst.SYS_CONFIGBASEDEFAULT,
ConfigKey = ConfigConst.CONFIG_PAGETAB,
ConfigValue = "false",
ConfigValue = "true",
Remark = "开启标签页",
SortCode = 7,
},

View File

@@ -12,7 +12,7 @@
<ItemGroup>
<ProjectReference Include="..\ThingsGateway.Admin.Core\ThingsGateway.Admin.Core.csproj" />
<PackageReference Include="MiniExcel" Version="1.31.2" />
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.3.5" />
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.3.7" />
</ItemGroup>
</Project>

View File

@@ -1,12 +1,12 @@
#region copyright
#region copyright
//------------------------------------------------------------------------------
// <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊȫ<EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD>ֶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
// <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߱<EFBFBD><EFBFBD><EFBFBD>Diego<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
// Դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѭ<EFBFBD><EFBFBD><EFBFBD>ֿ<EFBFBD><EFBFBD>Ŀ<EFBFBD>ԴЭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD>
// GiteeԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://gitee.com/diego2098/ThingsGateway
// GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway
// ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/
// QQȺ<EFBFBD><EFBFBD>605534569
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
// QQ群:605534569
//------------------------------------------------------------------------------
#endregion
@@ -16,8 +16,7 @@ using Masa.Blazor.Presets;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.Extensions.DependencyInjection;
using System.Diagnostics;
using Microsoft.Extensions.Hosting;
using ThingsGateway.Foundation.Extension.String;
@@ -44,7 +43,7 @@ public partial class Login
/// <inheritdoc/>
protected override async Task OnParametersSetAsync()
{
if (Debugger.IsAttached)
if (App.WebHostEnvironment.IsDevelopment())
{
_loginModel.Account = "superAdmin";
_password = "111111";
@@ -54,7 +53,7 @@ public partial class Login
_configTitle = (await _serviceScope.ServiceProvider.GetService<IConfigService>().GetByConfigKeyAsync(ConfigConst.SYS_CONFIGBASEDEFAULT, ConfigConst.CONFIG_TITLE))?.ConfigValue;
_configRemark = (await _serviceScope.ServiceProvider.GetService<IConfigService>().GetByConfigKeyAsync(ConfigConst.SYS_CONFIGBASEDEFAULT, ConfigConst.CONFIG_REMARK))?.ConfigValue;
_showCaptcha = (await _serviceScope.ServiceProvider.GetService<IConfigService>().GetByConfigKeyAsync(ConfigConst.SYS_CONFIGBASEDEFAULT, ConfigConst.CONFIG_CAPTCHA_OPEN))?.ConfigValue?.ToBool(false) == true;
_welcome = "<EFBFBD><EFBFBD>ӭʹ<EFBFBD><EFBFBD>" + _configTitle + "!";
_welcome = "欢迎使用" + _configTitle + "!";
await base.OnParametersSetAsync();
}
@@ -102,11 +101,11 @@ public partial class Login
await _captcha.RefreshCode();
}
await PopupService.EnqueueSnackbarAsync(new("<EFBFBD><EFBFBD>¼<EFBFBD><EFBFBD><EFBFBD><EFBFBD>" + ": " + ret.Msg.ToString(), AlertTypes.Error));
await PopupService.EnqueueSnackbarAsync(new("登录错误" + ": " + ret.Msg.ToString(), AlertTypes.Error));
}
else
{
await PopupService.EnqueueSnackbarAsync(new("<EFBFBD><EFBFBD>¼<EFBFBD>ɹ<EFBFBD>", AlertTypes.Success));
await PopupService.EnqueueSnackbarAsync(new("登录成功", AlertTypes.Success));
await Task.Delay(500);
var userId = await _serviceScope.ServiceProvider.GetService<SysUserService>().GetIdByAccountAsync(_loginModel.Account);
var data = await _serviceScope.ServiceProvider.GetService<UserCenterService>().GetLoginDefaultRazorAsync(userId);
@@ -124,7 +123,7 @@ public partial class Login
await _captcha.RefreshCode();
}
await PopupService.EnqueueSnackbarAsync(new("<EFBFBD><EFBFBD>¼<EFBFBD><EFBFBD><EFBFBD><EFBFBD>", AlertTypes.Error));
await PopupService.EnqueueSnackbarAsync(new("登录错误", AlertTypes.Error));
}
}
private async Task<string> RefreshCode()

View File

@@ -1,12 +1,12 @@
#region copyright
#region copyright
//------------------------------------------------------------------------------
// <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊȫ<EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD>ֶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
// <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߱<EFBFBD><EFBFBD><EFBFBD>Diego<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
// Դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѭ<EFBFBD><EFBFBD><EFBFBD>ֿ<EFBFBD><EFBFBD>Ŀ<EFBFBD>ԴЭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD>
// GiteeԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://gitee.com/diego2098/ThingsGateway
// GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway
// ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/
// QQȺ<EFBFBD><EFBFBD>605534569
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
// QQ群:605534569
//------------------------------------------------------------------------------
#endregion
@@ -44,7 +44,7 @@ public partial class MainLayout
[Inject]
private UserResoures _userResoures { get; set; }
/// <summary>
/// ҳ<EFBFBD><EFBFBD>ˢ<EFBFBD><EFBFBD>
/// 页面刷新
/// </summary>
/// <returns></returns>
public async Task StateHasChangedAsync()

View File

@@ -5,8 +5,8 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.9.1.4" />
<PackageReference Include="SqlSugarCore" Version="5.1.4.117" />
<PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.9.1.5" />
<PackageReference Include="SqlSugarCore" Version="5.1.4.123" />
<PackageReference Include="UAParser" Version="3.1.47" />
<PackageReference Include="Yitter.IdGenerator" Version="1.0.14" />
</ItemGroup>

View File

@@ -1,8 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<PackageReference Include="Furion.Pure" Version="4.9.1.4" />
<PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.9.1.4" />
<PackageReference Include="Furion.Pure" Version="4.9.1.5" />
<PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.9.1.5" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>

View File

@@ -1,7 +1,7 @@
<Project>
<PropertyGroup>
<TargetFrameworks>net6.0;net8.0;</TargetFrameworks>
<Version>4.0.0.0</Version>
<Version>4.0.0.5</Version>
<LangVersion>latest</LangVersion>
<Authors>Diego</Authors>
<Product>ThingsGateway</Product>

View File

@@ -1,6 +1,10 @@
<Project>
<!--如果编译net45报错无支持用一下方法添加net45包-->
<!--VS顶部菜单栏 -> 视图 -> 其他 -> 程序包控制台
Install-Package Microsoft.NETFramework.ReferenceAssemblies.net45
-->
<PropertyGroup>
<Version>4.0.0.0</Version>
<Version>4.0.0.5</Version>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
<LangVersion>latest</LangVersion>
<TargetFrameworks>net45;netstandard2.0;net6.0;net8.0;</TargetFrameworks>

View File

@@ -134,21 +134,19 @@ internal class ModbusHelper
if (response[1] >= 0x80)//错误码
return new OperResult<byte[], FilterResult>(GetDescriptionByErrorCode(response[2])) { Content2 = FilterResult.Success };
if (response[1] <= 0x05)
if (response[1] <= 0x04)
{
if ((response.Length < response[2] + 5))
return new OperResult<byte[], FilterResult>("数据长度不足" + response.ToHexString()) { Content2 = FilterResult.Cache };
}
else
{
if ((response.Length < 8))
return new OperResult<byte[], FilterResult>("数据长度不足" + response.ToHexString()) { Content2 = FilterResult.Cache };
}
var data = response.SelectMiddle(0, response[2] != 0 ? response[2] + 5 : 8);
var data = response.SelectMiddle(0, response[1] <= 0x04 ? response[2] != 0 ? response[2] + 5 : 8 : 8);
if (crcCheck && !CRC16Utils.CheckCRC16(data))
return new OperResult<byte[], FilterResult>("Crc校验失败" + DataTransUtil.ByteToHexString(data, ' ')) { Content2 = FilterResult.Success };
return GetModbusData(send, data.RemoveLast(2));

View File

@@ -17,6 +17,10 @@ namespace ThingsGateway.Foundation.Adapter.Modbus
/// <inheritdoc/>
internal interface IModbusServer : IReadWrite
{
/// <summary>
/// 外部写入数据后,是否写入内存(下次读取实时更新否则需要内部调用Write)
/// </summary>
public bool WriteMemory { get; set; }
/// <summary>
/// 读写锁
/// </summary>

View File

@@ -18,15 +18,19 @@ namespace ThingsGateway.Foundation.Adapter.Modbus;
/// </summary>
public class ModbusSerialServer : ReadWriteDevicesSerialSessionBase, IModbusServer
{
/// <inheritdoc/>
public ModbusSerialServer(SerialSession serialSession) : base(serialSession)
{
ThingsGatewayBitConverter = new ThingsGatewayBitConverter(EndianType.Big);
RegisterByteLength = 2;
}
/// <summary>
/// 读写锁
/// </summary>
public EasyLock EasyLock { get; } = new();
/// <summary>
/// 接收外部写入时,传出变量地址/写入字节组/转换规则/客户端
/// </summary>
public Func<ModbusAddress, byte[], IThingsGatewayBitConverter, ISenderClient, Task<OperResult>> OnWriteData { get; set; }
/// <inheritdoc/>
public bool IsRtu => true;
/// <inheritdoc/>
public ConcurrentDictionary<byte, ByteBlock> ModbusServer01ByteBlocks { get; set; } = new();
@@ -39,22 +43,22 @@ public class ModbusSerialServer : ReadWriteDevicesSerialSessionBase, IModbusServ
/// <inheritdoc/>
public ConcurrentDictionary<byte, ByteBlock> ModbusServer04ByteBlocks { get; set; } = new();
/// <inheritdoc/>
public ModbusSerialServer(SerialSession serialSession) : base(serialSession)
{
ThingsGatewayBitConverter = new ThingsGatewayBitConverter(EndianType.Big);
RegisterByteLength = 2;
}
/// <inheritdoc/>
public bool MulStation { get; set; }
/// <summary>
/// 接收外部写入时,传出变量地址/写入字节组/转换规则/客户端
/// </summary>
public Func<ModbusAddress, byte[], IThingsGatewayBitConverter, ISenderClient, Task<OperResult>> OnWriteData { get; set; }
/// <inheritdoc/>
public byte Station { get; set; } = 1;
/// <summary>
/// <inheritdoc/>
public bool IsRtu => true;
/// </summary>
public bool WriteMemory { get; set; }
/// <inheritdoc/>
public override void Dispose()
{
@@ -87,6 +91,17 @@ public class ModbusSerialServer : ReadWriteDevicesSerialSessionBase, IModbusServ
return $"{base.GetAddressDescription()}{Environment.NewLine}{ModbusHelper.GetAddressDescription()}";
}
/// <inheritdoc/>
public void Init(ModbusAddress mAddress)
{
ModbusServer01ByteBlocks.GetOrAdd(mAddress.Station, a => new ByteBlock(new byte[ushort.MaxValue * 2]));
ModbusServer02ByteBlocks.GetOrAdd(mAddress.Station, a => new ByteBlock(new byte[ushort.MaxValue * 2]));
ModbusServer03ByteBlocks.GetOrAdd(mAddress.Station, a => new ByteBlock(new byte[ushort.MaxValue * 2]));
ModbusServer04ByteBlocks.GetOrAdd(mAddress.Station, a => new ByteBlock(new byte[ushort.MaxValue * 2]));
}
/// <inheritdoc/>
public override List<T> LoadSourceRead<T, T2>(List<T2> deviceVariables, int maxPack, int defaultIntervalTime)
{
@@ -161,35 +176,4 @@ public class ModbusSerialServer : ReadWriteDevicesSerialSessionBase, IModbusServ
Logger.LogError(ex, ToString());
}
}
/// <inheritdoc/>
public void Init(ModbusAddress mAddress)
{
ModbusServer01ByteBlocks.GetOrAdd(mAddress.Station, a =>
{
var data = new ByteBlock(ushort.MaxValue * 2);
data.SetLength(ushort.MaxValue * 2);
return data;
});
ModbusServer02ByteBlocks.GetOrAdd(mAddress.Station, a =>
{
var data = new ByteBlock(ushort.MaxValue * 2);
data.SetLength(ushort.MaxValue * 2);
return data;
});
ModbusServer03ByteBlocks.GetOrAdd(mAddress.Station, a =>
{
var data = new ByteBlock(ushort.MaxValue * 2);
data.SetLength(ushort.MaxValue * 2);
return data;
});
ModbusServer04ByteBlocks.GetOrAdd(mAddress.Station, a =>
{
var data = new ByteBlock(ushort.MaxValue * 2);
data.SetLength(ushort.MaxValue * 2);
return data;
});
}
}

View File

@@ -236,15 +236,17 @@ internal static class ModbusServerHelpers
if ((await modbusServer.OnWriteData(modbusServerMessage.ModbusAddress, modbusServerMessage.Content, modbusServer.ThingsGatewayBitConverter, client)).IsSuccess)
{
WriteSuccess(modbusServer.IsRtu, client, modbusServerMessage);
//var result = modbusServer.Write(modbusServerMessage.ModbusAddress.ToString(), coreData.ByteToBoolArray(modbusServerMessage.Length));
//if (result.IsSuccess)
//{
// WriteSuccess(modbusServer, modbusServerMessage);
//}
//else
//{
// WriteError(modbusServer, modbusServerMessage);
//}
if (modbusServer.WriteMemory)
{
var result = modbusServer.Write(modbusServerMessage.ModbusAddress.ToString(), coreData.ByteToBoolArray(modbusServerMessage.Length));
if (result.IsSuccess)
WriteSuccess(modbusServer.IsRtu, client, modbusServerMessage);
else
WriteError(modbusServer.IsRtu, client, modbusServerMessage);
}
else
WriteSuccess(modbusServer.IsRtu, client, modbusServerMessage);
}
else
{
@@ -273,16 +275,16 @@ internal static class ModbusServerHelpers
if ((await modbusServer.OnWriteData(modbusServerMessage.ModbusAddress, modbusServerMessage.Content, modbusServer.ThingsGatewayBitConverter, client)).IsSuccess)
{
WriteSuccess(modbusServer.IsRtu, client, modbusServerMessage);
//var result = modbusServer.Write(modbusServerMessage.ModbusAddress.ToString(), coreData);
//if (result.IsSuccess)
//{
// WriteSuccess(modbusServer, modbusServerMessage);
//}
//else
//{
// WriteError(modbusServer, modbusServerMessage);
//}
if (modbusServer.WriteMemory)
{
var result = modbusServer.Write(modbusServerMessage.ModbusAddress.ToString(), coreData);
if (result.IsSuccess)
WriteSuccess(modbusServer.IsRtu, client, modbusServerMessage);
else
WriteError(modbusServer.IsRtu, client, modbusServerMessage);
}
else
WriteSuccess(modbusServer.IsRtu, client, modbusServerMessage);
}
else
{

View File

@@ -19,11 +19,6 @@ namespace ThingsGateway.Foundation.Adapter.Modbus;
/// </summary>
public class ModbusTcpServer : ReadWriteDevicesTcpServerBase, IModbusServer
{
/// <summary>
/// 读写锁
/// </summary>
public EasyLock EasyLock { get; } = new();
/// <inheritdoc/>
public ModbusTcpServer(TcpService tcpService) : base(tcpService)
{
@@ -31,6 +26,10 @@ public class ModbusTcpServer : ReadWriteDevicesTcpServerBase, IModbusServer
RegisterByteLength = 2;
}
/// <summary>
/// 读写锁
/// </summary>
public EasyLock EasyLock { get; } = new();
/// <inheritdoc/>
public bool IsRtu => false;
@@ -69,6 +68,10 @@ public class ModbusTcpServer : ReadWriteDevicesTcpServerBase, IModbusServer
/// </summary>
[Description("默认站点")]
public byte Station { get; set; } = 1;
/// <summary>
/// <inheritdoc/>
/// </summary>
public bool WriteMemory { get; set; }
@@ -107,30 +110,12 @@ public class ModbusTcpServer : ReadWriteDevicesTcpServerBase, IModbusServer
/// <inheritdoc/>
public void Init(ModbusAddress mAddress)
{
ModbusServer01ByteBlocks.GetOrAdd(mAddress.Station, a =>
{
var data = new ByteBlock(ushort.MaxValue * 2);
data.SetLength(ushort.MaxValue * 2);
return data;
});
ModbusServer02ByteBlocks.GetOrAdd(mAddress.Station, a =>
{
var data = new ByteBlock(ushort.MaxValue * 2);
data.SetLength(ushort.MaxValue * 2);
return data;
});
ModbusServer03ByteBlocks.GetOrAdd(mAddress.Station, a =>
{
var data = new ByteBlock(ushort.MaxValue * 2);
data.SetLength(ushort.MaxValue * 2);
return data;
});
ModbusServer04ByteBlocks.GetOrAdd(mAddress.Station, a =>
{
var data = new ByteBlock(ushort.MaxValue * 2);
data.SetLength(ushort.MaxValue * 2);
return data;
});
ModbusServer01ByteBlocks.GetOrAdd(mAddress.Station, a => new ByteBlock(new byte[ushort.MaxValue * 2]));
ModbusServer02ByteBlocks.GetOrAdd(mAddress.Station, a => new ByteBlock(new byte[ushort.MaxValue * 2]));
ModbusServer03ByteBlocks.GetOrAdd(mAddress.Station, a => new ByteBlock(new byte[ushort.MaxValue * 2]));
ModbusServer04ByteBlocks.GetOrAdd(mAddress.Station, a => new ByteBlock(new byte[ushort.MaxValue * 2]));
}
/// <inheritdoc/>

View File

@@ -440,6 +440,7 @@ namespace ThingsGateway.Foundation.Adapter.Siemens
}
finally
{
SetDataAdapter();
await base.Connected(client, e);
}
}

View File

@@ -21,7 +21,7 @@ namespace ThingsGateway.Foundation.Extension.String;
public static class StringExtensions
{
/// <summary>
/// 转换布尔值
/// 转换布尔值,注意 10onoff truefalse 都会对应转换
/// </summary>
/// <param name="value"></param>
/// <returns></returns>

View File

@@ -1,7 +1,5 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net45;netstandard2.0;net6.0;net8.0;</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />

View File

@@ -40,6 +40,14 @@ namespace ThingsGateway.Foundation.Sockets
{
this.Protocol = Protocol.Tcp;
}
/// <summary>
/// <inheritdoc/>
/// </summary>
/// <returns></returns>
public override string ToString()
{
return $"{nameof(SocketClient)}:{IP}:{Port}";
}
#region

View File

@@ -338,7 +338,8 @@ namespace ThingsGateway.Foundation.Sockets
this.m_online = true;
this.SetSocket(socket);
this.BeginReceive();
_ = Task.Factory.StartNew(this.PrivateOnConnected, new ConnectedEventArgs());
this.PrivateOnConnected(new ConnectedEventArgs()).GetFalseAwaitResult();
//_ = Task.Factory.StartNew(this.PrivateOnConnected, new ConnectedEventArgs());
}
finally
{
@@ -394,7 +395,7 @@ namespace ThingsGateway.Foundation.Sockets
{
throw new TimeoutException("连接超时");
}
Success(socket);
await Success(socket);
#else
using CancellationTokenSource cancellationTokenSource = new();
@@ -411,7 +412,7 @@ namespace ThingsGateway.Foundation.Sockets
}
else
{
Success(socket);
await Success(socket);
}
}
else
@@ -424,12 +425,13 @@ namespace ThingsGateway.Foundation.Sockets
#endif
void Success(Socket socket)
async Task Success(Socket socket)
{
this.m_online = true;
this.SetSocket(socket);
this.BeginReceive();
_ = Task.Factory.StartNew(this.PrivateOnConnected, new ConnectedEventArgs());
await this.PrivateOnConnected(new ConnectedEventArgs());
//_ = Task.Factory.StartNew(this.PrivateOnConnected, new ConnectedEventArgs());
}
}
finally

View File

@@ -608,6 +608,7 @@ namespace ThingsGateway.Foundation.Sockets
this.OnAccepted(e);
}
}
catch (ObjectDisposedException) { }
catch (Exception ex)
{
this.Logger.Exception(ex);

View File

@@ -1,6 +1,6 @@
<Project>
<PropertyGroup>
<Version>4.0.0.0</Version>
<Version>4.0.0.5</Version>
<LangVersion>latest</LangVersion>
<ImplicitUsings>enable</ImplicitUsings>
<TargetFrameworks>net6.0;net8.0;</TargetFrameworks>

View File

@@ -43,14 +43,16 @@ public abstract class CollectBase : DriverBase
public override async Task AfterStopAsync()
{
await base.AfterStopAsync();
//去除全局设备变量
lock (_globalDeviceData.CollectDevices)
{
_globalDeviceData.CollectDevices.RemoveWhere(it => it.Id == DeviceId);
}
await base.AfterStopAsync();
}
public override void Init(DeviceRunTime device)
{
base.Init(device);

View File

@@ -10,22 +10,15 @@
//------------------------------------------------------------------------------
#endregion
using Mapster;
using Microsoft.Extensions.Logging;
using System.Collections.Concurrent;
using ThingsGateway.Foundation.Extension.ConcurrentQueue;
using ThingsGateway.Foundation.Extension.Generic;
namespace ThingsGateway.Gateway.Application;
/// <summary>
/// 上传插件
/// </summary>
public abstract class UpLoadBaseWithCache<DeviceT, VariableT> : UpLoadBase
public abstract class UpLoadBaseWithCache : UpLoadBase
{
/// <summary>
/// <inheritdoc/><br></br>
@@ -33,50 +26,17 @@ public abstract class UpLoadBaseWithCache<DeviceT, VariableT> : UpLoadBase
/// </summary>
public override DriverPropertyBase DriverPropertys => _uploadPropertyWithCache;
/// <summary>
/// mapster配置
/// </summary>
protected virtual TypeAdapterConfig _config { get; set; }
/// <summary>
/// 是否需要设备上传默认true
/// </summary>
protected virtual bool _device { get; } = true;
/// <summary>
/// <inheritdoc cref="DriverPropertys"/>
/// </summary>
protected abstract UploadPropertyWithCache _uploadPropertyWithCache { get; }
/// <summary>
/// 是否需要变量上传默认true
/// </summary>
protected virtual bool _variable { get; } = true;
/// <summary>
/// 离线缓存
/// </summary>
protected LiteDBCache CacheDb { get; set; }
/// <inheritdoc/>
protected override void Dispose(bool disposing)
{
try
{
_globalDeviceData?.AllVariables?.ForEach(a => a.VariableValueChange -= VariableValueChange);
_globalDeviceData?.CollectDevices?.ForEach(a =>
{
a.DeviceStatusChange -= DeviceStatusChange;
});
CacheDb?.Litedb?.SafeDispose();
base.Dispose(disposing);
}
catch (Exception ex)
{
LogMessage?.LogWarning(ex);
}
}
public override void Init(DeviceRunTime device)
{
base.Init(device);
@@ -93,6 +53,20 @@ public abstract class UpLoadBaseWithCache<DeviceT, VariableT> : UpLoadBase
CollectDevices = _globalDeviceData.CollectDevices.Where(a => device.DeviceVariableRunTimes.Select(b => b.DeviceId).Contains(a.Id)).ToList();
}
}
/// <inheritdoc/>
protected override void Dispose(bool disposing)
{
try
{
CacheDb?.Litedb?.SafeDispose();
base.Dispose(disposing);
}
catch (Exception ex)
{
LogMessage?.LogWarning(ex);
}
}
/// <summary>
/// 初始化
/// </summary>
@@ -101,167 +75,21 @@ public abstract class UpLoadBaseWithCache<DeviceT, VariableT> : UpLoadBase
protected override void Init(ISenderClient client = null)
{
CacheDb = new LiteDBCache(DeviceId.ToString(), CurrentDevice.PluginName);
if (!_uploadPropertyWithCache.IsInterval)
{
if (_device)
CollectDevices.ForEach(a => { a.DeviceStatusChange += DeviceStatusChange; });
if (_variable)
CurrentDevice.DeviceVariableRunTimes.ForEach(a => { a.VariableValueChange += VariableValueChange; });
}
if (_uploadPropertyWithCache.CycleInterval <= 100) _uploadPropertyWithCache.CycleInterval = 100;
if (_uploadPropertyWithCache.UploadInterval <= 1000) _uploadPropertyWithCache.UploadInterval = 1000;
_exVariableTimerTick = new(_uploadPropertyWithCache.UploadInterval);
_exDeviceTimerTick = new(_uploadPropertyWithCache.UploadInterval);
}
/// <inheritdoc/>
protected override Task ProtectedBeforStartAsync(CancellationToken cancellationToken)
{
_token = cancellationToken;
_ = Task.Factory.StartNew(IntervalInsert);
_ = Task.Factory.StartNew(CheckCacheDb);
return base.ProtectedBeforStartAsync(cancellationToken);
}
#region
/// <summary>
/// 设备内存队列
/// </summary>
protected CancellationToken _token;
protected ConcurrentQueue<DeviceT> _collectDeviceRunTimes = new();
/// <summary>
/// 变量内存队列
/// </summary>
protected ConcurrentQueue<VariableT> _collectVariableRunTimes = new();
protected TimerTick _exDeviceTimerTick;
protected TimerTick _exVariableTimerTick;
private CancellationToken _token;
protected abstract void AddCache(List<CacheItem> cacheItems, IEnumerable<VariableT> dev);
protected abstract void AddCache(List<CacheItem> cacheItems, IEnumerable<DeviceT> dev);
/// <summary>
/// 添加设备队列,超限后会入缓存
/// </summary>
/// <param name="deviceData"></param>
protected void AddDeviceQueue(DeviceT deviceData)
{
//检测队列长度,超限存入缓存数据库
if (_collectDeviceRunTimes.Count > _uploadPropertyWithCache.QueueMaxCount)
{
List<DeviceT> list = null;
lock (_collectDeviceRunTimes)
{
if (_collectDeviceRunTimes.Count > _uploadPropertyWithCache.QueueMaxCount)
{
list = _collectDeviceRunTimes.ToListWithDequeue();
}
}
if (list != null)
{
var devData = list.ChunkBetter(_uploadPropertyWithCache.SplitSize);
var cacheItems = new List<CacheItem>();
AddCache(devData, cacheItems);
if (cacheItems.Count > 0)
CacheDb.Cache.Insert(cacheItems);
}
}
_collectDeviceRunTimes.Enqueue(deviceData);
}
/// <summary>
/// 添加变量队列,超限后会入缓存
/// </summary>
/// <param name="variableData"></param>
protected void AddVariableQueue(VariableT variableData)
{
//检测队列长度,超限存入缓存数据库
if (_collectVariableRunTimes.Count > _uploadPropertyWithCache.QueueMaxCount)
{
List<VariableT> list = null;
lock (_collectVariableRunTimes)
{
if (_collectVariableRunTimes.Count > _uploadPropertyWithCache.QueueMaxCount)
{
list = _collectVariableRunTimes.ToListWithDequeue();
}
}
if (list != null)
{
var devData = list.ChunkBetter(_uploadPropertyWithCache.SplitSize);
var cacheItems = new List<CacheItem>();
AddCache(devData, cacheItems);
if (cacheItems.Count > 0)
CacheDb.Cache.Insert(cacheItems);
}
}
_collectVariableRunTimes.Enqueue(variableData);
}
protected virtual void DeviceStatusChange(DeviceRunTime collectDeviceRunTime)
{
if (!CurrentDevice.KeepRun)
return;
if (_device)
if (_uploadPropertyWithCache?.IsInterval != true)
{
AddDeviceQueue(collectDeviceRunTime.Adapt<DeviceT>(_config ?? TypeAdapterConfig.GlobalSettings));
}
}
protected virtual void VariableValueChange(DeviceVariableRunTime deviceVariableRunTime)
{
if (!CurrentDevice.KeepRun)
return;
if (_variable)
if (_uploadPropertyWithCache?.IsInterval != true)
{
AddVariableQueue(deviceVariableRunTime.Adapt<VariableT>(_config ?? TypeAdapterConfig.GlobalSettings));
}
}
private void AddCache(IEnumerable<IEnumerable<VariableT>> devData, List<CacheItem> cacheItems)
{
try
{
foreach (var dev in devData)
{
AddCache(cacheItems, dev);
}
}
catch (Exception ex)
{
LogMessage.LogWarning(ex, "缓存失败");
}
}
private void AddCache(IEnumerable<IEnumerable<DeviceT>> devData, List<CacheItem> cacheItems)
{
try
{
foreach (var dev in devData)
{
AddCache(cacheItems, dev);
}
}
catch (Exception ex)
{
LogMessage.LogWarning(ex, "缓存失败");
}
}
private async Task CheckCacheDb()
{
while (!_token.IsCancellationRequested)
@@ -269,7 +97,6 @@ public abstract class UpLoadBaseWithCache<DeviceT, VariableT> : UpLoadBase
try
{
CacheDb.DeleteOldData(_uploadPropertyWithCache.CahceMaxLength);
}
catch (Exception ex)
{
@@ -278,58 +105,6 @@ public abstract class UpLoadBaseWithCache<DeviceT, VariableT> : UpLoadBase
await Delay(30000, _token);
}
}
private async Task IntervalInsert()
{
while (!_token.IsCancellationRequested)
{
if (CurrentDevice?.KeepRun == false)
{
await Delay(_uploadPropertyWithCache.CycleInterval, _token);
continue;
}
//间隔上传
if (_uploadPropertyWithCache.IsInterval)
{
try
{
if (_variable)
if (_exVariableTimerTick.IsTickHappen())
{
//间隔推送全部变量
var varList = CurrentDevice.DeviceVariableRunTimes.Adapt<List<VariableT>>(_config ?? TypeAdapterConfig.GlobalSettings);
foreach (var variableData in varList)
{
AddVariableQueue(variableData);
}
}
}
catch (Exception ex)
{
LogMessage.LogWarning(ex, "添加队列失败");
}
try
{
if (_device)
if (_exDeviceTimerTick.IsTickHappen())
{
var devList = CollectDevices.Adapt<List<DeviceT>>(_config ?? TypeAdapterConfig.GlobalSettings);
foreach (var devData in devList)
{
AddDeviceQueue(devData);
}
}
}
catch (Exception ex)
{
LogMessage.LogWarning(ex, "添加队列失败");
}
}
await Delay(_uploadPropertyWithCache.CycleInterval, _token);
}
}
#endregion
}

View 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 Mapster;
using Microsoft.Extensions.Logging;
using System.Collections.Concurrent;
using ThingsGateway.Foundation.Extension.ConcurrentQueue;
using ThingsGateway.Foundation.Extension.Generic;
namespace ThingsGateway.Gateway.Application;
/// <summary>
/// 上传插件
/// </summary>
public abstract class UpLoadBaseWithCacheT<DeviceT, VariableT> : UpLoadBase
{
/// <summary>
/// <inheritdoc/><br></br>
/// 实现<see cref="_uploadPropertyWithCache"/>
/// </summary>
public override DriverPropertyBase DriverPropertys => _uploadPropertyWithCache;
/// <summary>
/// mapster配置
/// </summary>
protected virtual TypeAdapterConfig _config { get; set; }
/// <summary>
/// 是否需要设备上传默认true
/// </summary>
protected virtual bool _device { get; } = true;
/// <summary>
/// <inheritdoc cref="DriverPropertys"/>
/// </summary>
protected abstract UploadPropertyWithCacheT _uploadPropertyWithCache { get; }
/// <summary>
/// 是否需要变量上传默认true
/// </summary>
protected virtual bool _variable { get; } = true;
/// <summary>
/// 离线缓存
/// </summary>
protected LiteDBCache CacheDb { get; set; }
/// <inheritdoc/>
protected override void Dispose(bool disposing)
{
try
{
_globalDeviceData?.AllVariables?.ForEach(a => a.VariableValueChange -= VariableValueChange);
_globalDeviceData?.CollectDevices?.ForEach(a =>
{
a.DeviceStatusChange -= DeviceStatusChange;
});
CacheDb?.Litedb?.SafeDispose();
base.Dispose(disposing);
}
catch (Exception ex)
{
LogMessage?.LogWarning(ex);
}
}
public override void Init(DeviceRunTime device)
{
base.Init(device);
if (_uploadPropertyWithCache.IsAllVariable)
{
device.DeviceVariableRunTimes = _globalDeviceData.AllVariables;
CollectDevices = _globalDeviceData.CollectDevices.ToList();
}
else
{
var variables = _globalDeviceData.AllVariables.Where(a =>
a.VariablePropertys.ContainsKey(device.Id)).ToList();
device.DeviceVariableRunTimes = variables;
CollectDevices = _globalDeviceData.CollectDevices.Where(a => device.DeviceVariableRunTimes.Select(b => b.DeviceId).Contains(a.Id)).ToList();
}
}
/// <summary>
/// 初始化
/// </summary>
/// <param name="device">当前设备</param>
/// <param name="client">链路,共享链路时生效</param>
protected override void Init(ISenderClient client = null)
{
CacheDb = new LiteDBCache(DeviceId.ToString(), CurrentDevice.PluginName);
if (!_uploadPropertyWithCache.IsInterval)
{
if (_device)
CollectDevices.ForEach(a => { a.DeviceStatusChange += DeviceStatusChange; });
if (_variable)
CurrentDevice.DeviceVariableRunTimes.ForEach(a => { a.VariableValueChange += VariableValueChange; });
}
if (_uploadPropertyWithCache.CycleInterval <= 50) _uploadPropertyWithCache.CycleInterval = 50;
if (_uploadPropertyWithCache.UploadInterval <= 100) _uploadPropertyWithCache.UploadInterval = 100;
_exVariableTimerTick = new(_uploadPropertyWithCache.UploadInterval);
_exDeviceTimerTick = new(_uploadPropertyWithCache.UploadInterval);
}
/// <inheritdoc/>
protected override Task ProtectedBeforStartAsync(CancellationToken cancellationToken)
{
_token = cancellationToken;
_ = Task.Factory.StartNew(IntervalInsert);
_ = Task.Factory.StartNew(CheckCacheDb);
return base.ProtectedBeforStartAsync(cancellationToken);
}
#region
/// <summary>
/// 设备内存队列
/// </summary>
protected ConcurrentQueue<DeviceT> _collectDeviceRunTimes = new();
/// <summary>
/// 变量内存队列
/// </summary>
protected ConcurrentQueue<VariableT> _collectVariableRunTimes = new();
protected TimerTick _exDeviceTimerTick;
protected TimerTick _exVariableTimerTick;
private CancellationToken _token;
protected abstract void AddCache(List<CacheItem> cacheItems, IEnumerable<VariableT> dev);
protected abstract void AddCache(List<CacheItem> cacheItems, IEnumerable<DeviceT> dev);
/// <summary>
/// 添加设备队列,超限后会入缓存
/// </summary>
/// <param name="deviceData"></param>
private void AddDeviceQueue(DeviceT deviceData)
{
//检测队列长度,超限存入缓存数据库
if (_collectDeviceRunTimes.Count > _uploadPropertyWithCache.QueueMaxCount)
{
List<DeviceT> list = null;
lock (_collectDeviceRunTimes)
{
if (_collectDeviceRunTimes.Count > _uploadPropertyWithCache.QueueMaxCount)
{
list = _collectDeviceRunTimes.ToListWithDequeue();
}
}
if (list != null)
{
var devData = list.ChunkBetter(_uploadPropertyWithCache.SplitSize);
var cacheItems = new List<CacheItem>();
AddCache(devData, cacheItems);
if (cacheItems.Count > 0)
CacheDb.Cache.Insert(cacheItems);
}
}
_collectDeviceRunTimes.Enqueue(deviceData);
}
/// <summary>
/// 添加变量队列,超限后会入缓存
/// </summary>
/// <param name="variableData"></param>
private void AddVariableQueue(VariableT variableData)
{
//检测队列长度,超限存入缓存数据库
if (_collectVariableRunTimes.Count > _uploadPropertyWithCache.QueueMaxCount)
{
List<VariableT> list = null;
lock (_collectVariableRunTimes)
{
if (_collectVariableRunTimes.Count > _uploadPropertyWithCache.QueueMaxCount)
{
list = _collectVariableRunTimes.ToListWithDequeue();
}
}
if (list != null)
{
var devData = list.ChunkBetter(_uploadPropertyWithCache.SplitSize);
var cacheItems = new List<CacheItem>();
AddCache(devData, cacheItems);
if (cacheItems.Count > 0)
CacheDb.Cache.Insert(cacheItems);
}
}
_collectVariableRunTimes.Enqueue(variableData);
}
protected virtual void DeviceStatusChange(DeviceRunTime collectDeviceRunTime)
{
if (!CurrentDevice.KeepRun)
return;
if (_device)
if (_uploadPropertyWithCache?.IsInterval != true)
{
AddDeviceQueue(collectDeviceRunTime.Adapt<DeviceT>(_config ?? TypeAdapterConfig.GlobalSettings));
}
}
protected virtual void VariableValueChange(DeviceVariableRunTime deviceVariableRunTime)
{
if (!CurrentDevice.KeepRun)
return;
if (_variable)
if (_uploadPropertyWithCache?.IsInterval != true)
{
AddVariableQueue(deviceVariableRunTime.Adapt<VariableT>(_config ?? TypeAdapterConfig.GlobalSettings));
}
}
private void AddCache(IEnumerable<IEnumerable<VariableT>> devData, List<CacheItem> cacheItems)
{
try
{
foreach (var dev in devData)
{
AddCache(cacheItems, dev);
}
}
catch (Exception ex)
{
LogMessage.LogWarning(ex, "缓存失败");
}
}
private void AddCache(IEnumerable<IEnumerable<DeviceT>> devData, List<CacheItem> cacheItems)
{
try
{
foreach (var dev in devData)
{
AddCache(cacheItems, dev);
}
}
catch (Exception ex)
{
LogMessage.LogWarning(ex, "缓存失败");
}
}
private async Task CheckCacheDb()
{
while (!_token.IsCancellationRequested)
{
try
{
CacheDb.DeleteOldData(_uploadPropertyWithCache.CahceMaxLength);
}
catch (Exception ex)
{
LogMessage.LogWarning(ex, "删除缓存失败");
}
await Delay(30000, _token);
}
}
private async Task IntervalInsert()
{
while (!_token.IsCancellationRequested)
{
if (CurrentDevice?.KeepRun == false)
{
await Delay(_uploadPropertyWithCache.CycleInterval, _token);
continue;
}
//间隔上传
if (_uploadPropertyWithCache.IsInterval)
{
try
{
if (_variable)
if (_exVariableTimerTick.IsTickHappen())
{
//间隔推送全部变量
var varList = CurrentDevice.DeviceVariableRunTimes.Adapt<List<VariableT>>(_config ?? TypeAdapterConfig.GlobalSettings);
foreach (var variableData in varList)
{
AddVariableQueue(variableData);
}
}
}
catch (Exception ex)
{
LogMessage.LogWarning(ex, "添加队列失败");
}
try
{
if (_device)
if (_exDeviceTimerTick.IsTickHappen())
{
var devList = CollectDevices.Adapt<List<DeviceT>>(_config ?? TypeAdapterConfig.GlobalSettings);
foreach (var devData in devList)
{
AddDeviceQueue(devData);
}
}
}
catch (Exception ex)
{
LogMessage.LogWarning(ex, "添加队列失败");
}
}
await Delay(_uploadPropertyWithCache.CycleInterval, _token);
}
}
#endregion
}

View File

@@ -39,18 +39,7 @@ public class UploadPropertyWithCache : DriverPropertyBase
[DeviceProperty("列表分割大小", "默认1千条")]
public virtual int SplitSize { get; set; } = 1000;
/// <summary>
/// 是否间隔上传
/// </summary>
[DeviceProperty("是否间隔上传", "False时为变化检测上传")]
public virtual bool IsInterval { get; set; } = false;
/// <summary>
/// 上传间隔时间
/// </summary>
[DeviceProperty("上传间隔时间", "最小1000ms")]
public virtual int UploadInterval { get; set; } = 1000;
[DeviceProperty("是否选择全部变量", "")] public bool IsAllVariable { get; set; } = false;
[DeviceProperty("是否选择全部变量", "")] public virtual bool IsAllVariable { get; set; } = false;
}

View File

@@ -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
namespace ThingsGateway.Gateway.Application;
/// <summary>
/// <inheritdoc/>
/// </summary>
public class UploadPropertyWithCacheT : DriverPropertyBase
{
/// <summary>
/// 线程循环间隔
/// </summary>
[DeviceProperty("线程循环间隔", "最小50ms")]
public virtual int CycleInterval { get; set; } = 1000;
/// <summary>
/// 内存队列最大条数
/// </summary>
[DeviceProperty("内存队列最大条数", "默认2w条")]
public virtual int QueueMaxCount { get; set; } = 20000;
/// <summary>
/// 离线缓存大小限制
/// </summary>
[DeviceProperty("离线缓存文件大小限制", "默认1024mb")]
public virtual int CahceMaxLength { get; set; } = 1024;
/// <summary>
/// 列表分割大小
/// </summary>
[DeviceProperty("列表分割大小", "默认1千条")]
public virtual int SplitSize { get; set; } = 1000;
/// <summary>
/// 是否间隔上传
/// </summary>
[DeviceProperty("是否间隔上传", "False时为变化检测上传")]
public virtual bool IsInterval { get; set; } = false;
/// <summary>
/// 上传间隔时间
/// </summary>
[DeviceProperty("上传间隔时间", "最小100ms")]
public virtual int UploadInterval { get; set; } = 1000;
[DeviceProperty("是否选择全部变量", "")] public bool IsAllVariable { get; set; } = false;
}

View File

@@ -44,7 +44,7 @@ public class CollectDeviceService : DeviceService<CollectDevice>, ITransient
/// <inheritdoc/>
[OperDesc("复制设备与变量")]
[OperDesc("复制设备与变量", IsRecordPar = false)]
public virtual async Task CopyDevAndVarAsync(IEnumerable<CollectDevice> input)
{
var variableService = _serviceScope.ServiceProvider.GetService<VariableService>();

View File

@@ -10,6 +10,7 @@
//------------------------------------------------------------------------------
#endregion
using Furion.DependencyInjection;
using Furion.FriendlyException;
using Mapster;
@@ -30,6 +31,7 @@ using Yitter.IdGenerator;
namespace ThingsGateway.Gateway.Application;
[Injection(Proxy = typeof(OperDispatchProxy))]
public abstract class DeviceService<T> : DbRepository<T> where T : Device, new()
{
protected readonly IFileService _fileService;
@@ -233,8 +235,8 @@ public abstract class DeviceService<T> : DbRepository<T> where T : Device, new()
}
deviceDicts.TryGetValue(devData.RedundantDeviceId, out var redundantDevice);
//设备实体没有包含插件名称,手动插入
devExport.Add(ExportHelpers.PluginName, devData.PluginName);
////设备实体没有包含插件名称,手动插入
//devExport.Add(ExportHelpers.PluginName, devData.PluginName);
//设备实体没有包含冗余设备名称,手动插入
devExport.Add(ExportHelpers.RedundantDeviceName, redundantDevice?.Name);
@@ -374,22 +376,22 @@ public abstract class DeviceService<T> : DbRepository<T> where T : Device, new()
{
var device = ((ExpandoObject)item).ConvertToEntity<T>(true);
#region
//转化插件名称
var hasPlugin = item.TryGetValue(ExportHelpers.PluginName, out var pluginObj);
////转化插件名称
//var hasPlugin = item.TryGetValue(ExportHelpers.PluginName, out var pluginObj);
if (pluginObj == null || !driverPluginFullNameDict.TryGetValue(pluginObj.ToString(), out var plugin))
{
//找不到对应的插件
importPreviewOutput.HasError = true;
importPreviewOutput.Results.Add((row++, false, $"{ExportHelpers.PluginName}不存在"));
return;
}
//if (pluginObj == null || !driverPluginFullNameDict.TryGetValue(pluginObj.ToString(), out var plugin))
//{
// //找不到对应的插件
// importPreviewOutput.HasError = true;
// importPreviewOutput.Results.Add((row++, false, $"{ExportHelpers.PluginName}不存在"));
// return;
//}
//转化冗余设备名称
var hasRedundant = item.TryGetValue(ExportHelpers.PluginName, out var redundantObj);
var hasRedundant = item.TryGetValue(ExportHelpers.RedundantDeviceName, out var redundantObj);
#endregion
//设备ID、冗余设备ID都需要手动补录
if (hasRedundant && deviceDicts.TryGetValue(redundantObj.ToString(), out var rendundantDevice))
if (hasRedundant && redundantObj != null && deviceDicts.TryGetValue(redundantObj.ToString(), out var rendundantDevice))
{
device.RedundantDeviceId = rendundantDevice.Id;
}

View File

@@ -173,7 +173,7 @@ public class DriverPluginService : ISingleton
}
return plugins;
}, false);
}, true);
return data;
}
}
@@ -267,7 +267,19 @@ public class DriverPluginService : ISingleton
}, true);
return data;
}
static T GetCustomAttributeRecursive<T>(PropertyInfo property) where T : Attribute
{
var attribute = property.GetCustomAttribute<T>(false);
if (attribute == null && property.DeclaringType.BaseType != null)
{
var baseProperty = property.DeclaringType.BaseType.GetProperties().FirstOrDefault(p => p.Name == property.Name);
if (baseProperty != null)
{
attribute = GetCustomAttributeRecursive<T>(baseProperty);
}
}
return attribute;
}
/// <summary>
/// 获取插件的属性值
/// </summary>
@@ -278,7 +290,7 @@ public class DriverPluginService : ISingleton
var data = _serviceScope.ServiceProvider.GetService<MemoryCache>().GetOrCreate($"{nameof(GetDriverProperties)}", cacheKey, c =>
{
var data = driver.DriverPropertys?.GetType().GetProperties().SelectMany(it =>
new[] { new { memberInfo = it, attribute = it.GetCustomAttribute<DevicePropertyAttribute>() } })
new[] { new { memberInfo = it, attribute = GetCustomAttributeRecursive<DevicePropertyAttribute>(it) } })
.Where(x => x.attribute != null).ToList()
.SelectMany(it => new[]
{
@@ -305,7 +317,7 @@ public class DriverPluginService : ISingleton
var data = _serviceScope.ServiceProvider.GetService<MemoryCache>().GetOrCreate($"{nameof(GetDriverVariableProperties)}", cacheKey, c =>
{
var data = driver.VariablePropertys?.GetType().GetProperties()?.SelectMany(it =>
new[] { new { memberInfo = it, attribute = it.GetCustomAttribute<VariablePropertyAttribute>() } })
new[] { new { memberInfo = it, attribute = GetCustomAttributeRecursive<VariablePropertyAttribute>(it) } })
?.Where(x => x.attribute != null).ToList()
?.SelectMany(it => new[]
{
@@ -380,7 +392,7 @@ public class DriverPluginService : ISingleton
/// <param name="deviceProperties">插件属性,检索相同名称的属性后写入</param>
public void SetDriverProperties(DriverBase driver, List<DependencyProperty> deviceProperties)
{
var pluginPropertys = driver.DriverPropertys?.GetType().GetProperties().Where(a => a.GetCustomAttribute(typeof(DevicePropertyAttribute)) != null)?.ToList();
var pluginPropertys = driver.DriverPropertys?.GetType().GetProperties().Where(a => GetCustomAttributeRecursive<DevicePropertyAttribute>(a) != null)?.ToList();
foreach (var propertyInfo in pluginPropertys ?? new())
{
var deviceProperty = deviceProperties.FirstOrDefault(x => x.PropertyName == propertyInfo.Name);

View File

@@ -15,8 +15,7 @@
<PackageReference Include="CS-Script" Version="4.8.8" />
<!--CS-Script与Furion冲突直接安装覆盖版本-->
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="4.7.0" />
<PackageReference Include="MQTTnet" Version="4.3.1.873" />
<PackageReference Include="SqlSugar.TDengineCore" Version="3.2.0" />
<PackageReference Include="SqlSugar.TDengineCore" Version="3.4.0" />
</ItemGroup>
<ItemGroup>

View File

@@ -17,7 +17,7 @@ using System.Text;
namespace ThingsGateway.Gateway.Application;
/// <summary>
/// <see cref="HistoryValue"/> Master规则
/// <see cref="Encoding"/> Master规则
/// </summary>
public class EncodingMapper : IRegister
{

View File

@@ -23,7 +23,7 @@ namespace ThingsGateway.Gateway.Application;
/// </summary>
public class CollectDeviceWorker : DeviceWorker
{
private GlobalDeviceData _globalDeviceData;
public CollectDeviceWorker(IServiceScopeFactory serviceScopeFactory, IHostApplicationLifetime appLifetime) : base(serviceScopeFactory, appLifetime)
{
_logger = _serviceScope.ServiceProvider.GetService<ILoggerFactory>().CreateLogger("南向设备服务");
@@ -49,6 +49,10 @@ public class CollectDeviceWorker : DeviceWorker
await StopOtherHostService();
//停止全部采集线程
await RemoveAllDeviceThreadAsync();
//清空内存列表
_globalDeviceData.CollectDevices.Clear();
//创建全部采集线程
await CreatAllDeviceThreadsAsync();
//开始其他后台服务
@@ -74,8 +78,8 @@ public class CollectDeviceWorker : DeviceWorker
{
var alarmHostService = BackgroundServiceUtil.GetBackgroundService<AlarmWorker>();
var uploadDeviceHostService = BackgroundServiceUtil.GetBackgroundService<UploadDeviceWorker>();
await alarmHostService.StartAsync();
await uploadDeviceHostService.StartAsync();
await alarmHostService.StartAsync();
}
/// <summary>
@@ -197,6 +201,7 @@ public class CollectDeviceWorker : DeviceWorker
{
await _easyLock?.WaitAsync();
_driverPluginService = _serviceScope.ServiceProvider.GetService<DriverPluginService>();
_globalDeviceData = _serviceScope.ServiceProvider.GetService<GlobalDeviceData>();
//重启采集线程,会启动其他后台服务
await RestartDeviceThreadAsync();
await WhileExecuteAsync(stoppingToken);

View File

@@ -49,7 +49,7 @@ public abstract class DeviceWorker : BackgroundService
/// </summary>
public List<DriverBase> DriverBases => _deviceThreads
.Where(a => a.DriverBases.Any(b => b.CurrentDevice != null))
.SelectMany(a => a.DriverBases).ToList();
.SelectMany(a => a.DriverBases).OrderByDescending(a => a.CurrentDevice.DeviceStatus).ToList();
/// <summary>
/// 设备子线程列表

View File

@@ -99,9 +99,9 @@ public class UploadDeviceWorker : DeviceWorker
{
if (!_stoppingToken.IsCancellationRequested)
{
_logger.LogInformation("正在获取北向组态信息");
_logger.LogInformation("正在获取北向设备组态信息");
var deviceRunTimes = (_serviceScope.ServiceProvider.GetService<UploadDeviceService>().GetDeviceRuntime());
_logger.LogInformation("获取北向组态信息完成");
_logger.LogInformation("获取北向设备组态信息完成");
foreach (var uploadDeviceRunTime in deviceRunTimes.Where(a => !deviceRunTimes.Any(b => a.Id == b.RedundantDeviceId && b.IsRedundant)))
{
if (!_stoppingToken.IsCancellationRequested)

View File

@@ -1,12 +1,12 @@
#region copyright
#region copyright
//------------------------------------------------------------------------------
// <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊȫ<EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD>ֶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
// <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߱<EFBFBD><EFBFBD><EFBFBD>Diego<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
// Դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѭ<EFBFBD><EFBFBD><EFBFBD>ֿ<EFBFBD><EFBFBD>Ŀ<EFBFBD>ԴЭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD>
// GiteeԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://gitee.com/diego2098/ThingsGateway
// GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway
// ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/
// QQȺ<EFBFBD><EFBFBD>605534569
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
// QQ群:605534569
//------------------------------------------------------------------------------
#endregion
@@ -32,7 +32,7 @@ namespace ThingsGateway.Gateway.Blazor
try
{
await OnSaveAsync.InvokeAsync(Content);
//await InvokeAsync(async () => await PopupService.EnqueueSnackbarAsync("<EFBFBD>ɹ<EFBFBD>", AlertTypes.Success));
//await InvokeAsync(async () => await PopupService.EnqueueSnackbarAsync("成功", AlertTypes.Success));
await ClosePopupAsync();
}
catch (Exception ex)

View File

@@ -29,7 +29,7 @@
@layout MainLayout
@using ThingsGateway.Admin.Core;
@if (IsMobile)
@* @if (IsMobile)
{
@GetAppDataTable()
}
@@ -67,7 +67,9 @@ else
@GetAppDataTable()
</MCol>
</MRow>
}
} *@
@GetAppDataTable()
<ImportExcel @ref=_importExcel Import="SaveDeviceImportAsync" Preview="DeviceImportAsync" />

View File

@@ -35,7 +35,7 @@ public partial class CollectDevicePage : BaseComponentBase
List<CollectDevice> _devices = new();
List<DriverPlugin> _driverPlugins;
ImportExcel _importExcel;
string _searchName;
//string _searchName;
[Inject]
AjaxService _ajaxService { get; set; }
[Inject]

View File

@@ -19,7 +19,7 @@
@using Masa.Blazor.Presets;
@using System.IO;
@using Microsoft.AspNetCore.Authorization;
@using SqlSugar;
@using ThingsGateway.Admin.Blazor;
@using ThingsGateway.Admin.Core;
@@ -48,11 +48,11 @@
@if (_tabNumber == 1)
{
<MRow NoGutters>
<MCol Md=2 Cols="12">
@* <MCol Md=2 Cols="12">
<MCard Class="ma-2" Style=@($"height: calc(100vh - {BlazorResourceConst.DefaultHeight + 80}px );")>
<MCardTitle>
<MTextField Dense Style="max-width:200px;" HideDetails=@("auto") Class="mx-2 my-1" @bind-Value="_collectDeviceGroupSearchName"
<MTextField Dense Style="max-width:200px;" HideDetails=@("auto") Class="mx-2 my-1" @bind-Value="_collectDeviceSearchName"
Outlined Label=@typeof(CollectDevice).GetDescription(nameof(CollectDevice.DeviceGroup)) />
</MCardTitle>
@@ -64,7 +64,7 @@
}
} )
Items="_collectDeviceGroups" ItemText="r=>r" ItemChildren="r=>null"
Search="@_collectDeviceGroupSearchName"
Search="@_collectDeviceSearchName"
Activatable ItemKey=@(r=>r)>
<LabelContent>
<span title=@context.Item>
@@ -73,12 +73,14 @@
</LabelContent>
</MTreeview>
</MCard>
</MCol>
<MCol Md=3 Cols="12">
</MCol> *@
<MCol Md=5 Cols="12">
<MCard Height=@($"calc(100vh - {BlazorResourceConst.DefaultHeight + 80}px; )") Style="overflow-y:auto;" Flat Class="ml-2 my-4">
<MTextField Dense Style="max-width:200px;" HideDetails=@("auto") Class="mx-2 my-1" @bind-Value="_collectDeviceSearchName"
Outlined Label=@typeof(CollectDevice).GetDescription(nameof(CollectDevice.Name)) />
<MVirtualScroll Context="item" Height=@($"calc(100vh - {BlazorResourceConst.DefaultHeight+100}px)") OverscanCount=2 ItemSize="60" Items="_collectDriverBases">
<MVirtualScroll Context="item" Height=@($"calc(100vh - {BlazorResourceConst.DefaultHeight+140}px)") OverscanCount=2 ItemSize="60" Items="_collectDriverBases.WhereIF(!_collectDeviceSearchName.IsNullOrEmpty(),a=>a.CurrentDevice.Name.Contains(_collectDeviceSearchName)).ToList()">
<ItemContent>
@if (item.CurrentDevice != null)
@@ -250,10 +252,10 @@
@if (_tabNumber == 2)
{
<MRow>
<MCol Md=2 Cols="12">
@* <MCol Md=2 Cols="12">
<MCard Class="ma-2" Style=@($"height: calc(100vh - {BlazorResourceConst.DefaultHeight + 80}px); )")>
<MCardTitle>
<MTextField Dense Style="max-width:200px;" HideDetails=@("auto") Class="mx-2 my-1" @bind-Value="_uploadDeviceGroupSearchName"
<MTextField Dense Style="max-width:200px;" HideDetails=@("auto") Class="mx-2 my-1" @bind-Value="_uploadDeviceSearchName"
Outlined Label=@typeof(Device).GetDescription(nameof(Device.DeviceGroup)) />
</MCardTitle>
<MTreeview Style=@($"height: calc(100vh - {BlazorResourceConst.DefaultHeight+240}px);overflow-y:auto") Dense TItem="string" TKey="string" ActiveChanged=@(async a=>
@@ -265,7 +267,7 @@
}
} )
Items="_uploadDeviceGroups" ItemText="r=>r" ItemChildren="r=>null"
Search="@_uploadDeviceGroupSearchName"
Search="@_uploadDeviceSearchName"
Activatable ItemKey=@(r=>r)>
<LabelContent>
<span title=@context.Item>
@@ -274,11 +276,13 @@
</LabelContent>
</MTreeview>
</MCard>
</MCol>
<MCol Md=3 Cols="12">
</MCol> *@
<MCol Md=5 Cols="12">
<MCard Height=@($"calc(100vh - {BlazorResourceConst.DefaultHeight+80}px)") Style="overflow-y:auto;" Flat Class="ml-2 my-4">
<MTextField Dense Style="max-width:200px;" HideDetails=@("auto") Class="mx-2 my-1" @bind-Value="_uploadDeviceSearchName"
Outlined Label=@typeof(CollectDevice).GetDescription(nameof(CollectDevice.Name)) />
<MVirtualScroll Context="item" Height=@($"calc(100vh - {BlazorResourceConst.DefaultHeight+100}px)") OverscanCount=2 ItemSize="60" Items="_uploadDriverBases">
<MVirtualScroll Context="item" Height=@($"calc(100vh - {BlazorResourceConst.DefaultHeight+140}px)") OverscanCount=2 ItemSize="60" Items="_uploadDriverBases.WhereIF(!_uploadDeviceSearchName.IsNullOrEmpty(),a=>a.CurrentDevice.Name.Contains(_uploadDeviceSearchName)).ToList()">
<ItemContent>
@if (item.CurrentDevice != null)

View File

@@ -12,8 +12,6 @@
using BlazorComponent;
using Mapster;
using Masa.Blazor;
using Microsoft.AspNetCore.Components;
@@ -30,10 +28,11 @@ namespace ThingsGateway.Gateway.Blazor;
public partial class DeviceStatusPage : IDisposable
{
readonly PeriodicTimer _periodicTimer = new(TimeSpan.FromSeconds(3));
private string _collectDeviceGroup;
private bool _isShowDetailUI;
List<string> _collectDeviceGroups = new();
string _collectDeviceGroupSearchName;
//List<string> _collectDeviceGroups = new();
//string _collectDeviceGroupSearchName;
//private string _collectDeviceSearchName;
string _collectDeviceSearchName;
List<CollectBase> _collectDriverBases = new();
CollectBase _collectDriverItem;
BootstrapDynamicComponent _driverComponent;
@@ -42,9 +41,10 @@ public partial class DeviceStatusPage : IDisposable
bool _isAllRestart;
bool _isRestart;
StringNumber _tabNumber;
private string _uploadDeviceGroup;
List<string> _uploadDeviceGroups = new();
string _uploadDeviceGroupSearchName;
//private string _uploadDeviceSearchName;
//List<string> _uploadDeviceGroups = new();
//string _uploadDeviceGroupSearchName;
string _uploadDeviceSearchName;
List<DriverBase> _uploadDriverBases = new();
DriverBase _uploadDriverItem;
AlarmWorker _alarmWorker { get; set; }
@@ -121,8 +121,8 @@ public partial class DeviceStatusPage : IDisposable
void CollectDeviceQuery()
{
_collectDeviceGroups = _globalDeviceData.CollectDevices.Adapt<List<CollectDevice>>()?.Select(a => a.DeviceGroup)?.Where(a => a != null).Distinct()?.ToList() ?? new();
_collectDriverBases = _collectDeviceWorker?.DriverBases?.WhereIF(!_collectDeviceGroup.IsNullOrEmpty(), a => a.CurrentDevice?.DeviceGroup == _collectDeviceGroup).Select(a => (CollectBase)a).ToList() ?? new();
//_collectDeviceGroups = _globalDeviceData.CollectDevices?.Select(a => a.DeviceGroup)?.Where(a => !a.IsNullOrEmpty()).Distinct()?.ToList() ?? new();
_collectDriverBases = _collectDeviceWorker?.DriverBases?.WhereIF(!_collectDeviceSearchName.IsNullOrEmpty(), a => a.CurrentDevice?.Name.Contains(_collectDeviceSearchName) == true).Select(a => (CollectBase)a).ToList() ?? new();
}
async Task DeviceRedundantThreadAsync(long devId)
{
@@ -207,10 +207,6 @@ public partial class DeviceStatusPage : IDisposable
{
try
{
{
_collectDeviceGroups = _globalDeviceData.CollectDevices.Adapt<List<CollectDevice>>()?.Select(a => a.DeviceGroup)?.Where(a => a != null).Distinct()?.ToList() ?? new();
_collectDriverBases = _collectDeviceWorker?.DriverBases?.WhereIF(!_collectDeviceGroup.IsNullOrEmpty(), a => a.CurrentDevice?.DeviceGroup == _collectDeviceGroup).Select(a => (CollectBase)a).ToList() ?? new();
}
if (_collectDriverBases?.FirstOrDefault()?.CurrentDevice == null || _collectDeviceWorker?.DriverBases.Count != _collectDriverBases.Count)
{
CollectDeviceQuery();
@@ -248,8 +244,8 @@ public partial class DeviceStatusPage : IDisposable
void UploadDeviceQuery()
{
_uploadDeviceGroups = _uploadDeviceWorker.DriverBases.Select(a => a.CurrentDevice)?.Select(a => a.DeviceGroup)?.Where(a => a != null).Distinct()?.ToList() ?? new();
_uploadDriverBases = _uploadDeviceWorker?.DriverBases?.WhereIF(!_uploadDeviceGroup.IsNullOrEmpty(), a => a.CurrentDevice?.DeviceGroup == _uploadDeviceGroup).ToList() ?? new();
//_uploadDeviceGroups = _uploadDeviceWorker.DriverBases.Select(a => a.CurrentDevice)?.Select(a => a.DeviceGroup)?.Where(a => a != null).Distinct()?.ToList() ?? new();
_uploadDriverBases = _uploadDeviceWorker?.DriverBases?.WhereIF(!_uploadDeviceSearchName.IsNullOrEmpty(), a => a.CurrentDevice?.Name.Contains(_uploadDeviceSearchName) == true).ToList() ?? new();
}
async Task UpRestartAsync(long devId)
{

View File

@@ -30,7 +30,7 @@
@inject UserResoures UserResoures
@layout MainLayout
@if (IsMobile)
@* @if (IsMobile)
{
@GetAppDataTable()
@@ -69,7 +69,8 @@ else
</MCol>
</MRow>
}
} *@
@GetAppDataTable()
<ImportExcel @ref=_importExcel Import="SaveDeviceImportAsync" Preview="DeviceImportAsync" />

View File

@@ -32,7 +32,7 @@ public partial class DeviceVariablePage
ImportExcel _importExcel;
Dictionary<long, List<string>> _otherMethods = new();
string _searchName;
//string _searchName;
List<Device> _uploadDevices = new();

View File

@@ -30,7 +30,7 @@
@inherits BaseComponentBase
@inject UserResoures UserResoures
@layout MainLayout
@if (IsMobile)
@* @if (IsMobile)
{
@GetAppDataTable()
@@ -69,7 +69,11 @@ else
@GetAppDataTable()
</MCol>
</MRow>
}
} *@
@GetAppDataTable()
@code {
RenderFragment GetAppDataTable()
{

View File

@@ -34,7 +34,7 @@ public partial class DeviceVariableRunTimePage
private IAppDataTable _datatable;
private List<DeviceTree> _deviceGroups = new();
private EventCallback<string> _onWrite;
private string _searchName;
//private string _searchName;
/// <summary>
/// 设备名称
/// </summary>

View File

@@ -29,7 +29,7 @@
@layout MainLayout
@using ThingsGateway.Admin.Core;
@if (IsMobile)
@* @if (IsMobile)
{
@GetAppDataTable()
}
@@ -67,8 +67,9 @@ else
@GetAppDataTable()
</MCol>
</MRow>
}
} *@
@GetAppDataTable()
<ImportExcel @ref=_importExcel Import="SaveDeviceImportAsync" Preview="DeviceImportAsync" />

View File

@@ -35,7 +35,7 @@ public partial class UploadDevicePage
List<Device> _devices = new();
List<DriverPlugin> _driverPlugins;
ImportExcel _importExcel;
string _searchName;
//string _searchName;
[Inject]
AjaxService _ajaxService { get; set; }
[Inject]

View File

@@ -2,7 +2,6 @@
<ItemGroup>
<ProjectReference Include="..\..\admin\ThingsGateway.Admin.Blazor\ThingsGateway.Admin.Blazor.csproj" />
<ProjectReference Include="..\..\admin\ThingsGateway.Components\ThingsGateway.Components.csproj" />
<ProjectReference Include="..\ThingsGateway.Gateway.Application\ThingsGateway.Gateway.Application.csproj" />
</ItemGroup>
</Project>

View File

@@ -12,10 +12,8 @@
namespace ThingsGateway.Gateway.Core;
/// <summary>
/// 历史报警表
/// 报警变量
/// </summary>
[IgnoreSqlTable]
[SugarTable("historyAlarm", TableDescription = "历史报警表")]
public class AlarmVariable : PrimaryIdEntity
{
/// <inheritdoc cref="DeviceVariable.Name"/>

View File

@@ -1,6 +1,6 @@
<Project>
<PropertyGroup>
<Version>4.0.0.0</Version>
<Version>4.0.0.5</Version>
<LangVersion>latest</LangVersion>
<ImplicitUsings>enable</ImplicitUsings>
<TargetFrameworks>net6.0;net8.0;</TargetFrameworks>
@@ -14,10 +14,6 @@
</PropertyGroup>
<!--<PropertyGroup>
<EnableDynamicLoading>true</EnableDynamicLoading>
</PropertyGroup>-->
<ItemGroup>
<ProjectReference Include="..\..\gateway\ThingsGateway.Gateway.Application\ThingsGateway.Gateway.Application.csproj" >

View File

@@ -30,7 +30,7 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\gateway\ThingsGateway.Gateway.Blazor\ThingsGateway.Gateway.Blazor.csproj" >
<ProjectReference Include="..\..\gateway\ThingsGateway.Gateway.Blazor\ThingsGateway.Gateway.Blazor.csproj">
<Private>false</Private>
<CopyLocalSatelliteAssemblies>false</CopyLocalSatelliteAssemblies>
<ExcludeAssets>runtime</ExcludeAssets>

View File

@@ -16,8 +16,6 @@ using LiteDB;
using Microsoft.Extensions.Logging;
using MQTTnet.Diagnostics;
using System.Runtime.InteropServices;
using ThingsGateway.Foundation.Extension.ConcurrentQueue;
@@ -29,7 +27,7 @@ namespace ThingsGateway.Plugin.Kafka;
/// <summary>
/// Kafka消息生产
/// </summary>
public partial class KafkaProducer : UpLoadBaseWithCache<DeviceData, VariableData>
public partial class KafkaProducer : UpLoadBaseWithCacheT<DeviceData, VariableData>
{
/// <inheritdoc/>
public override Type DriverDebugUIType => null;
@@ -41,7 +39,7 @@ public partial class KafkaProducer : UpLoadBaseWithCache<DeviceData, VariableDat
protected override IReadWrite _readWrite => null;
protected override UploadPropertyWithCache _uploadPropertyWithCache => _driverPropertys;
protected override UploadPropertyWithCacheT _uploadPropertyWithCache => _driverPropertys;
/// <summary>
@@ -71,18 +69,19 @@ public partial class KafkaProducer : UpLoadBaseWithCache<DeviceData, VariableDat
#region Kafka
Enum.TryParse<SecurityProtocol>(_driverPropertys.SecurityProtocol, out var SecurityProtocol);
Enum.TryParse<SaslMechanism>(_driverPropertys.SaslMechanism, out var SaslMechanism);
//1、生产者配置
producerconfig = new ProducerConfig
{
BootstrapServers = _driverPropertys.BootStrapServers,
SecurityProtocol = SecurityProtocol,
SaslMechanism = SaslMechanism,
SaslUsername = _driverPropertys.SaslUsername,
SaslPassword = _driverPropertys.SaslPassword,
SecurityProtocol = _driverPropertys.SecurityProtocol,
SaslMechanism = _driverPropertys.SaslMechanism,
};
if (!string.IsNullOrEmpty(_driverPropertys.SaslUsername))
producerconfig.SaslUsername = _driverPropertys.SaslUsername;
if (!string.IsNullOrEmpty(_driverPropertys.SaslPassword))
producerconfig.SaslPassword = _driverPropertys.SaslPassword;
//2、创建生产者
producerBuilder = new ProducerBuilder<Null, string>(producerconfig);

View File

@@ -19,7 +19,7 @@ namespace ThingsGateway.Plugin.Kafka;
/// <summary>
/// MqttClient
/// </summary>
public partial class KafkaProducer : UpLoadBaseWithCache<DeviceData, VariableData>
public partial class KafkaProducer : UpLoadBaseWithCacheT<DeviceData, VariableData>
{
private const string devType = "dev";
private const string varType = "var";

View File

@@ -10,12 +10,14 @@
//------------------------------------------------------------------------------
#endregion
using Confluent.Kafka;
namespace ThingsGateway.Plugin.Kafka;
/// <summary>
/// kafka 生产者属性
/// </summary>
public class KafkaProducerProperty : UploadPropertyWithCache
public class KafkaProducerProperty : UploadPropertyWithCacheT
{
/// <summary>
/// 服务地址
@@ -53,12 +55,10 @@ public class KafkaProducerProperty : UploadPropertyWithCache
/// </summary>
[DeviceProperty("密码", "")]
public string SaslPassword { get; set; } = "none";
[DeviceProperty("SecurityProtocol", "")]
public string SecurityProtocol { get; set; } = "SaslPlaintext";
[DeviceProperty("SaslMechanism", "")]
public string SaslMechanism { get; set; } = "Plain";
[DeviceProperty("SecurityProtocol", "Plaintext, Ssl, SaslPlaintext, SaslSsl")]
public SecurityProtocol SecurityProtocol { get; set; } = SecurityProtocol.Plaintext;
[DeviceProperty("SaslMechanism", " Gssapi, Plain, ScramSha256, ScramSha512, OAuthBearer")]
public SaslMechanism SaslMechanism { get; set; } = SaslMechanism.Plain;
/// <summary>
/// 设备实体脚本

View File

@@ -78,13 +78,14 @@ public class ModbusSerialServer : UpLoadBase
DataFormat = _driverPropertys.DataFormat,
Station = _driverPropertys.Station,
CacheTimeout = _driverPropertys.CacheTimeout,
WriteMemory = _driverPropertys.WriteMemory,
MulStation = _driverPropertys.MulStation
};
var tags = CurrentDevice.DeviceVariableRunTimes
.Where(b => !string.IsNullOrEmpty(
b.GetPropertyValue(DeviceId, nameof(_variablePropertys.ServiceAddress)).Value))
b.GetPropertyValue(DeviceId, nameof(_variablePropertys.ServiceAddress))?.Value))
.ToList();
tags.ForEach(a =>

View File

@@ -67,6 +67,11 @@ public class ModbusSerialServerProperty : DriverPropertyBase
[DeviceProperty("允许写入", "")]
public bool DeviceRpcEnable { get; set; }
/// <summary>
/// 立即写入内存
/// </summary>
[DeviceProperty("立即写入内存", "")]
public bool WriteMemory { get; set; }
/// <summary>
/// 组包缓存超时ms
/// </summary>
[DeviceProperty("组包缓存超时", "某些设备性能较弱报文间需要间隔较长时间可以设置更长的组包缓存默认1000ms")]

View File

@@ -45,7 +45,7 @@ public class ModbusTcpDtu : CollectBase
var client1 = new TcpService();
((TcpService)client1).Setup(FoundataionConfig);
//载入配置
_plc = new((TcpService)client)
_plc = new((TcpService)client1)
{
DataFormat = _driverPropertys.DataFormat,
FrameTime = _driverPropertys.FrameTime,

View File

@@ -64,6 +64,7 @@ public class ModbusTcpServer : UpLoadBase
iPHost = new IPHost($"{_driverPropertys.IP}:{_driverPropertys.Port}");
}
FoundataionConfig.SetListenIPHosts(new IPHost[] { iPHost });
FoundataionConfig.SetMaxCount(30000);
var service = new TcpService();
service.Setup(FoundataionConfig);
//载入配置
@@ -72,12 +73,13 @@ public class ModbusTcpServer : UpLoadBase
DataFormat = _driverPropertys.DataFormat,
Station = _driverPropertys.Station,
CacheTimeout = _driverPropertys.CacheTimeout,
WriteMemory = _driverPropertys.WriteMemory,
MulStation = _driverPropertys.MulStation
};
var tags = CurrentDevice.DeviceVariableRunTimes
.Where(b => !string.IsNullOrEmpty(
b.GetPropertyValue(DeviceId, nameof(_variablePropertys.ServiceAddress)).Value))
b.GetPropertyValue(DeviceId, nameof(_variablePropertys.ServiceAddress))?.Value))
.ToList();
tags.ForEach(a =>

View File

@@ -48,6 +48,11 @@ public class ModbusTcpServerProperty : DriverPropertyBase
[DeviceProperty("允许写入", "")]
public bool DeviceRpcEnable { get; set; }
/// <summary>
/// 立即写入内存
/// </summary>
[DeviceProperty("立即写入内存", "")]
public bool WriteMemory { get; set; }
/// <summary>
/// 组包缓存超时ms
/// </summary>
[DeviceProperty("组包缓存超时", "某些设备性能较弱报文间需要间隔较长时间可以设置更长的组包缓存默认1000ms")]

View File

@@ -51,7 +51,7 @@
<ItemGroup>
<ProjectReference Include="..\..\gateway\ThingsGateway.Gateway.Blazor\ThingsGateway.Gateway.Blazor.csproj" >
<ProjectReference Include="..\..\gateway\ThingsGateway.Gateway.Blazor\ThingsGateway.Gateway.Blazor.csproj">
<Private>false</Private>
<CopyLocalSatelliteAssemblies>false</CopyLocalSatelliteAssemblies>
<ExcludeAssets>runtime</ExcludeAssets>

View File

@@ -24,7 +24,7 @@ namespace ThingsGateway.Plugin.Mqtt;
/// <summary>
/// IotSharpClient
/// </summary>
public partial class IotSharpClient : UpLoadBaseWithCache<DeviceData, VariableData>
public partial class IotSharpClient : UpLoadBaseWithCacheT<DeviceData, VariableData>
{
/// <inheritdoc/>
public override Type DriverDebugUIType => null;
@@ -35,7 +35,7 @@ public partial class IotSharpClient : UpLoadBaseWithCache<DeviceData, VariableDa
public override VariablePropertyBase VariablePropertys => _variablePropertys;
protected override IReadWrite _readWrite => null;
protected override UploadPropertyWithCache _uploadPropertyWithCache => _driverPropertys;
protected override UploadPropertyWithCacheT _uploadPropertyWithCache => _driverPropertys;
/// <summary>
/// <inheritdoc/>

View File

@@ -27,7 +27,7 @@ namespace ThingsGateway.Plugin.Mqtt;
/// <summary>
/// IotSharpClient
/// </summary>
public partial class IotSharpClient : UpLoadBaseWithCache<DeviceData, VariableData>
public partial class IotSharpClient : UpLoadBaseWithCacheT<DeviceData, VariableData>
{
/// <summary>
/// rpcmethodname存疑定为自定义方法在ThingsGateway上写入变量的方法固定为"Write"
@@ -112,7 +112,7 @@ public partial class IotSharpClient : UpLoadBaseWithCache<DeviceData, VariableDa
var tag = CurrentDevice.DeviceVariableRunTimes.FirstOrDefault(a => a.Name == item.Key);
if (tag != null)
{
var rpcEnable = tag.GetPropertyValue(DeviceId, nameof(_variablePropertys.VariableRpcEnable)).Value.ToBool(false) && _driverPropertys.DeviceRpcEnable;
var rpcEnable = tag.GetPropertyValue(DeviceId, nameof(_variablePropertys.VariableRpcEnable))?.Value?.ToBool() == true && _driverPropertys.DeviceRpcEnable;
if (!rpcEnable)
{
results.Add(item.Key, new OperResult("权限不足,变量不支持写入"));

View File

@@ -15,7 +15,7 @@ namespace ThingsGateway.Plugin.Mqtt;
/// <summary>
/// <inheritdoc/>
/// </summary>
public class IotSharpClientProperty : UploadPropertyWithCache
public class IotSharpClientProperty : UploadPropertyWithCacheT
{
/// <summary>

View File

@@ -26,7 +26,7 @@ namespace ThingsGateway.Plugin.Mqtt;
/// <summary>
/// MqttClient
/// </summary>
public partial class MqttClient : UpLoadBaseWithCache<DeviceData, VariableData>
public partial class MqttClient : UpLoadBaseWithCacheT<DeviceData, VariableData>
{
/// <inheritdoc/>
public override Type DriverDebugUIType => null;
@@ -37,7 +37,7 @@ public partial class MqttClient : UpLoadBaseWithCache<DeviceData, VariableData>
public override VariablePropertyBase VariablePropertys => _variablePropertys;
protected override IReadWrite _readWrite => null;
protected override UploadPropertyWithCache _uploadPropertyWithCache => _driverPropertys;
protected override UploadPropertyWithCacheT _uploadPropertyWithCache => _driverPropertys;
/// <summary>
/// <inheritdoc/>
@@ -69,14 +69,20 @@ public partial class MqttClient : UpLoadBaseWithCache<DeviceData, VariableData>
{
base.Init(client);
var mqttFactory = new MqttFactory();
_mqttClientOptions = mqttFactory.CreateClientOptionsBuilder()
var mqttClientOptionsBuilder = mqttFactory.CreateClientOptionsBuilder()
.WithClientId(_driverPropertys.ConnectId)
.WithCredentials(_driverPropertys.UserName, _driverPropertys.Password)//账密
.WithTcpServer(_driverPropertys.IP, _driverPropertys.Port)//服务器
.WithCleanSession(true)
.WithKeepAlivePeriod(TimeSpan.FromSeconds(120.0))
.WithoutThrowOnNonSuccessfulConnectResponse()
.WithoutThrowOnNonSuccessfulConnectResponse();
if (_driverPropertys.IsWebSocket)
_mqttClientOptions = mqttClientOptionsBuilder.WithWebSocketServer(a => a.WithUri(_driverPropertys.WebSocktUrl))
.Build();
else
_mqttClientOptions = mqttClientOptionsBuilder.WithTcpServer(_driverPropertys.IP, _driverPropertys.Port)//服务器
.Build();
_mqttSubscribeOptions = mqttFactory.CreateSubscribeOptionsBuilder()
.WithTopicFilter(
f =>

View File

@@ -32,7 +32,7 @@ namespace ThingsGateway.Plugin.Mqtt;
/// <summary>
/// MqttClient
/// </summary>
public partial class MqttClient : UpLoadBaseWithCache<DeviceData, VariableData>
public partial class MqttClient : UpLoadBaseWithCacheT<DeviceData, VariableData>
{
private const string devType = "dev";
private const string varType = "var";
@@ -134,7 +134,7 @@ public partial class MqttClient : UpLoadBaseWithCache<DeviceData, VariableData>
var tag = CurrentDevice.DeviceVariableRunTimes.FirstOrDefault(a => a.Name == rpcData.Key);
if (tag != null)
{
var rpcEnable = tag.GetPropertyValue(DeviceId, nameof(_variablePropertys.VariableRpcEnable)).Value.ToBool();
var rpcEnable = tag.GetPropertyValue(DeviceId, nameof(_variablePropertys.VariableRpcEnable))?.Value?.ToBool();
if (rpcEnable == true)
{

View File

@@ -15,7 +15,7 @@ namespace ThingsGateway.Plugin.Mqtt;
/// <summary>
/// <inheritdoc/>
/// </summary>
public class MqttClientProperty : UploadPropertyWithCache
public class MqttClientProperty : UploadPropertyWithCacheT
{
/// <summary>
@@ -29,6 +29,16 @@ public class MqttClientProperty : UploadPropertyWithCache
[DeviceProperty("端口", "")]
public override int Port { get; set; } = 1883;
/// <summary>
/// 是否websocket连接
/// </summary>
[DeviceProperty("是否WebSocket连接", "true=>websocketflase=>tcp")]
public bool IsWebSocket { get; set; } = false;
/// <summary>
/// WebSocktUrl
/// </summary>
[DeviceProperty("WebSocktUrl", "")]
public string WebSocktUrl { get; set; } = "ws://127.0.0.1:8083/mqtt";
/// <summary>
/// 账号
/// </summary>
[DeviceProperty("账号", "")]

View File

@@ -14,15 +14,18 @@ using Furion;
using Mapster;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using MQTTnet;
using MQTTnet.AspNetCore;
using MQTTnet.Internal;
using MQTTnet.Protocol;
using MQTTnet.Server;
using System.Collections.Concurrent;
using System.Net;
using System.Text;
using ThingsGateway.Admin.Application;
@@ -93,6 +96,7 @@ public class MqttServer : UpLoadBase
_mqttServer.InterceptingSubscriptionAsync -= MqttServer_InterceptingSubscriptionAsync; ;
_mqttServer?.SafeDispose();
}
_webHost?.Dispose();
_globalDeviceData?.AllVariables?.ForEach(a => a.VariableValueChange -= VariableValueChange);
_globalDeviceData?.CollectDevices?.ForEach(a =>
{
@@ -102,16 +106,32 @@ public class MqttServer : UpLoadBase
_collectVariableRunTimes.Clear();
base.Dispose(disposing);
}
private IWebHost _webHost { get; set; }
protected override void Init(ISenderClient client = null)
{
var mqttFactory = new MqttFactory();
var mqttServerOptions = mqttFactory.CreateServerOptionsBuilder()
.WithDefaultEndpointBoundIPAddress(string.IsNullOrEmpty(_driverPropertys.IP) ? null : IPAddress.Parse(_driverPropertys.IP))
.WithDefaultEndpointPort(_driverPropertys.Port)
.WithDefaultEndpoint()
.Build();
_mqttServer = mqttFactory.CreateMqttServer(mqttServerOptions);
//var mqttFactory = new MqttFactory();
//var mqttServerOptions = mqttFactory.CreateServerOptionsBuilder()
// .WithDefaultEndpointBoundIPAddress(string.IsNullOrEmpty(_driverPropertys.IP) ? null : IPAddress.Parse(_driverPropertys.IP))
// .WithDefaultEndpointPort(_driverPropertys.Port)
// .WithDefaultEndpoint()
// .Build();
//_mqttServer = mqttFactory.CreateMqttServer(mqttServerOptions);
var configuration = new ConfigurationBuilder()
.SetBasePath(Directory)
.Build();
var webBuilder = new WebHostBuilder()
.UseKestrel(
o =>
{
o.ListenAnyIP(_driverPropertys.Port, l => l.UseMqtt());
o.ListenAnyIP(_driverPropertys.WebSocketPort);
});
webBuilder.UseStartup<MqttServerStartup>();
_webHost = webBuilder.UseConfiguration(configuration)
.Build();
_mqttServer = _webHost.Services.GetService<MqttHostedServer>();
CollectDevices.Where(a => CurrentDevice.DeviceVariableRunTimes.Select(b => b.DeviceId).Contains(a.Id)).ForEach(a =>
{
@@ -121,11 +141,11 @@ public class MqttServer : UpLoadBase
{
a.VariableValueChange += VariableValueChange;
});
}
protected override async Task ProtectedBeforStartAsync(CancellationToken cancellationToken)
{
_ = _webHost.StartAsync(cancellationToken);
if (_mqttServer != null)
{
_mqttServer.ValidatingConnectionAsync += MqttServer_ValidatingConnectionAsync;
@@ -288,7 +308,7 @@ public class MqttServer : UpLoadBase
var tag = CurrentDevice.DeviceVariableRunTimes.FirstOrDefault(a => a.Name == rpcData.Key);
if (tag != null)
{
var rpcEnable = tag.GetPropertyValue(DeviceId, nameof(_variablePropertys.VariableRpcEnable)).Value.ToBool(false);
var rpcEnable = tag.GetPropertyValue(DeviceId, nameof(_variablePropertys.VariableRpcEnable))?.Value?.ToBool() == true;
if (!rpcEnable)
{
mqttRpcResult.Success = false;

View File

@@ -17,17 +17,18 @@ namespace ThingsGateway.Plugin.Mqtt;
public class MqttServerProperty : DriverPropertyBase
{
[DeviceProperty("是否选择全部变量", "")] public bool IsAllVariable { get; set; } = false;
/// <summary>
/// IP
/// </summary>
[DeviceProperty("IP", "留空则全部监听")]
public override string IP { get; set; } = "";
/// <summary>
/// 端口
/// </summary>
[DeviceProperty("端口", "")]
public override int Port { get; set; } = 1883;
/// <summary>
/// WebSocket端口
/// </summary>
[DeviceProperty("WebSocket端口", "")]
public int WebSocketPort { get; set; } = 8083;
/// <summary>
/// 允许连接的ID(前缀)
/// </summary>
[DeviceProperty("允许连接的ID(前缀)", "")]

View File

@@ -0,0 +1,63 @@
#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 Mapster;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using MQTTnet.AspNetCore;
using MQTTnet.Diagnostics;
namespace MQTTnet.Server;
/// <summary>
/// MqttServerStartup
/// </summary>
public class MqttServerStartup
{
/// <inheritdoc/>
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton(s =>
{
var serverOptionsBuilder = new MqttServerOptionsBuilder();
serverOptionsBuilder.WithDefaultEndpoint();
return serverOptionsBuilder.Build();
});
var logger = new MqttNetEventLogger();
services.AddSingleton<IMqttNetLogger>(logger);
services.AddSingleton<MqttHostedServer>();
//services.AddSingleton<IHostedService>(s => s.GetService<MqttHostedServer>());
////不再注册HostService,MqttServer的生命周期由插件完成
services.AddSingleton<MqttServer>(s => s.GetService<MqttHostedServer>());
services.AddMqttConnectionHandler();
services.AddConnections();
}
/// <inheritdoc/>
public void Configure(IApplicationBuilder app)
{
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapConnectionHandler<MqttConnectionHandler>(
"/mqtt",
httpConnectionDispatcherOptions => httpConnectionDispatcherOptions.WebSockets.SubProtocolSelector =
protocolList => protocolList.FirstOrDefault() ?? string.Empty);
});
}
}

View File

@@ -3,10 +3,15 @@
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
<Exec Command=" set dir=&quot;$(SolutionDir)web\ThingsGateway.Web.Entry\bin\$(Configuration)\$(TargetFramework)\Plugins\$(AssemblyName)&quot;&#xD;&#xA; if not exist %25dir%25 md %25dir%25 &#xD;&#xA;copy &quot;$(TargetDir)*Mqtt*.dll&quot; %25dir%25&#xD;&#xA;&#xD;&#xA;&#xD;&#xA;" />
<Exec Command=" set dir=&quot;$(SolutionDir)web\ThingsGateway.Web.Entry\bin\$(Configuration)\$(TargetFramework)\Plugins\$(AssemblyName)&quot;&#xD;&#xA; if not exist %25dir%25 md %25dir%25 &#xD;&#xA;copy &quot;$(TargetDir)*Mqtt*.dll&quot; %25dir%25&#xD;&#xA;&#xD;&#xA;copy &quot;$(TargetDir)*MQTTnet.AspNetCore*.dll&quot; %25dir%25&#xD;&#xA;" />
</Target>
<ItemGroup>
<PackageReference Include="MQTTnet.AspNetCore" Version="4.3.1.873" />
</ItemGroup>
<PropertyGroup>
<EnableDynamicLoading>true</EnableDynamicLoading>
</PropertyGroup>
</Project>

View File

@@ -45,7 +45,7 @@
<ItemGroup>
<ProjectReference Include="..\..\gateway\ThingsGateway.Gateway.Blazor\ThingsGateway.Gateway.Blazor.csproj" >
<ProjectReference Include="..\..\gateway\ThingsGateway.Gateway.Blazor\ThingsGateway.Gateway.Blazor.csproj">
<Private>false</Private>
<CopyLocalSatelliteAssemblies>false</CopyLocalSatelliteAssemblies>
<ExcludeAssets>runtime</ExcludeAssets>

View File

@@ -48,7 +48,7 @@ public class OPCUAClient : CollectBase
public override Task AfterStopAsync()
{
_plc?.Disconnect();
return Task.CompletedTask;
return base.AfterStopAsync();
}
protected override string GetAddressDescription()
{

View File

@@ -54,7 +54,7 @@
<ItemGroup>
<ProjectReference Include="..\..\gateway\ThingsGateway.Gateway.Blazor\ThingsGateway.Gateway.Blazor.csproj" >
<ProjectReference Include="..\..\gateway\ThingsGateway.Gateway.Blazor\ThingsGateway.Gateway.Blazor.csproj">
<Private>false</Private>
<CopyLocalSatelliteAssemblies>false</CopyLocalSatelliteAssemblies>
<ExcludeAssets>runtime</ExcludeAssets>

View File

@@ -16,8 +16,6 @@ using Mapster;
using Microsoft.Extensions.Logging;
using MQTTnet.Diagnostics;
using SqlSugar;
using ThingsGateway.Foundation.Extension.ConcurrentQueue;
@@ -28,7 +26,7 @@ namespace ThingsGateway.Plugin.QuestDB;
/// <summary>
/// SQLDB
/// </summary>
public partial class QuestDB : UpLoadBaseWithCache<DeviceData, QuestDBHistoryValue>
public partial class QuestDB : UpLoadBaseWithCacheT<DeviceData, QuestDBHistoryValue>
{
protected override bool _device => false;
protected override bool _variable => true;
@@ -41,7 +39,7 @@ public partial class QuestDB : UpLoadBaseWithCache<DeviceData, QuestDBHistoryVal
public override VariablePropertyBase VariablePropertys => _variablePropertys;
protected override IReadWrite _readWrite => null;
protected override UploadPropertyWithCache _uploadPropertyWithCache => _driverPropertys;
protected override UploadPropertyWithCacheT _uploadPropertyWithCache => _driverPropertys;
/// <summary>
/// <inheritdoc/>
@@ -59,7 +57,7 @@ public partial class QuestDB : UpLoadBaseWithCache<DeviceData, QuestDBHistoryVal
{
_config = new TypeAdapterConfig();
_config.ForType<DeviceVariableRunTime, QuestDBHistoryValue>()
.Map(dest => dest.Value, (src) => ValueReturn(src))
.Map(dest => dest.Value, src => src.Value == null ? string.Empty : src.Value.ToString() ?? string.Empty)
.Map(dest => dest.CollectTime, (src) => src.CollectTime < DateTime.MinValue ? DateTime.MinValue.ToUniversalTime() : src.CollectTime.ToUniversalTime())//注意sqlsugar插入时无时区直接utc时间
.Map(dest => dest.CreateTime, (src) => DateTime.UtcNow)
;//注意sqlsugar插入时无时区直接utc时间

View File

@@ -57,5 +57,5 @@ public class QuestDBHistoryValue
/// 变量值
/// </summary>
[Description("变量值")]
public double Value { get; set; }
public string Value { get; set; }
}

View File

@@ -22,7 +22,6 @@ using System.ComponentModel.DataAnnotations;
using System.Reflection;
using ThingsGateway.Foundation.Extension.Generic;
using ThingsGateway.Foundation.Extension.String;
using Yitter.IdGenerator;
@@ -31,7 +30,7 @@ namespace ThingsGateway.Plugin.QuestDB;
/// <summary>
/// MqttClient
/// </summary>
public partial class QuestDB : UpLoadBaseWithCache<DeviceData, QuestDBHistoryValue>
public partial class QuestDB : UpLoadBaseWithCacheT<DeviceData, QuestDBHistoryValue>
{
private const string devType = "dev";
private const string varType = "var";
@@ -39,18 +38,6 @@ public partial class QuestDB : UpLoadBaseWithCache<DeviceData, QuestDBHistoryVal
private readonly QuestDBVariableProperty _variablePropertys = new();
private volatile bool success = true;
private static object ValueReturn(DeviceVariableRunTime src)
{
var data = src.Value?.ToString()?.ToBool();
if (data != null)
{
return data;
}
else
{
return src.Value;
}
}
protected override void AddCache(List<CacheItem> cacheItems, IEnumerable<QuestDBHistoryValue> dev)
{

View File

@@ -17,7 +17,7 @@ namespace ThingsGateway.Plugin.QuestDB;
/// <summary>
/// <inheritdoc/>
/// </summary>
public class QuestDBProperty : UploadPropertyWithCache
public class QuestDBProperty : UploadPropertyWithCacheT
{
public DbType DbType { get; set; } = DbType.QuestDB;

View File

@@ -14,8 +14,6 @@ using LiteDB;
using Microsoft.Extensions.Logging;
using MQTTnet.Diagnostics;
using RabbitMQ.Client;
using ThingsGateway.Foundation.Extension.ConcurrentQueue;
@@ -27,7 +25,7 @@ namespace ThingsGateway.Plugin.RabbitMQ;
/// <summary>
/// Kafka消息生产
/// </summary>
public partial class RabbitMQProducer : UpLoadBaseWithCache<DeviceData, VariableData>
public partial class RabbitMQProducer : UpLoadBaseWithCacheT<DeviceData, VariableData>
{
/// <inheritdoc/>
public override Type DriverDebugUIType => null;
@@ -39,7 +37,7 @@ public partial class RabbitMQProducer : UpLoadBaseWithCache<DeviceData, Variable
protected override IReadWrite _readWrite => null;
protected override UploadPropertyWithCache _uploadPropertyWithCache => _driverPropertys;
protected override UploadPropertyWithCacheT _uploadPropertyWithCache => _driverPropertys;
/// <summary>

View File

@@ -21,7 +21,7 @@ namespace ThingsGateway.Plugin.RabbitMQ;
/// <summary>
/// MqttClient
/// </summary>
public partial class RabbitMQProducer : UpLoadBaseWithCache<DeviceData, VariableData>
public partial class RabbitMQProducer : UpLoadBaseWithCacheT<DeviceData, VariableData>
{
private const string devType = "dev";
private const string varType = "var";

View File

@@ -17,7 +17,7 @@ namespace ThingsGateway.Plugin.RabbitMQ;
/// <summary>
/// kafka 生产者属性
/// </summary>
public class RabbitMQProducerProperty : UploadPropertyWithCache
public class RabbitMQProducerProperty : UploadPropertyWithCacheT
{
/// <summary>
/// IP

View File

@@ -16,8 +16,6 @@ using Mapster;
using Microsoft.Extensions.Logging;
using MQTTnet.Diagnostics;
using ThingsGateway.Foundation.Extension.ConcurrentQueue;
using ThingsGateway.Foundation.Sockets;
@@ -28,7 +26,7 @@ namespace ThingsGateway.Plugin.SQLDB;
/// <summary>
/// SQLDB
/// </summary>
public partial class SQLDB : UpLoadBaseWithCache<DeviceData, SQLHistoryValue>
public partial class SQLDB : UpLoadBaseWithCacheT<DeviceData, SQLHistoryValue>
{
protected override bool _device => false;
protected override bool _variable => _driverPropertys.IsHisDB;
@@ -41,7 +39,7 @@ public partial class SQLDB : UpLoadBaseWithCache<DeviceData, SQLHistoryValue>
public override VariablePropertyBase VariablePropertys => _variablePropertys;
protected override IReadWrite _readWrite => null;
protected override UploadPropertyWithCache _uploadPropertyWithCache => _driverPropertys;
protected override UploadPropertyWithCacheT _uploadPropertyWithCache => _driverPropertys;
/// <summary>
/// <inheritdoc/>

View File

@@ -30,7 +30,7 @@ namespace ThingsGateway.Plugin.SQLDB;
/// <summary>
/// MqttClient
/// </summary>
public partial class SQLDB : UpLoadBaseWithCache<DeviceData, SQLHistoryValue>
public partial class SQLDB : UpLoadBaseWithCacheT<DeviceData, SQLHistoryValue>
{
private const string devType = "dev";
private const string varType = "var";

View File

@@ -17,7 +17,7 @@ namespace ThingsGateway.Plugin.SQLDB;
/// <summary>
/// <inheritdoc/>
/// </summary>
public class SQLDBProperty : UploadPropertyWithCache
public class SQLDBProperty : UploadPropertyWithCacheT
{
[DeviceProperty("是否实时表", "true=>实时表更新")] public bool IsReadDB { get; set; } = false;
[DeviceProperty("是否历史表", "true=>历史存储(按月分表)")] public bool IsHisDB { get; set; } = true;

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

View File

@@ -0,0 +1,9 @@
using SqlSugar;
namespace ThingsGateway.Plugin.SQLHisAlarm;
[SugarTable("historyAlarm", TableDescription = "历史报警表")]
internal class HistoryAlarm : AlarmVariable
{
}

View File

@@ -0,0 +1,178 @@
#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 LiteDB;
using Mapster;
using Microsoft.Extensions.Logging;
using ThingsGateway.Foundation.Extension.ConcurrentQueue;
using ThingsGateway.Foundation.Sockets;
using Yitter.IdGenerator;
namespace ThingsGateway.Plugin.SQLHisAlarm;
/// <summary>
/// SQLDB
/// </summary>
public partial class SQLHisAlarm : UpLoadBaseWithCache
{
/// <inheritdoc/>
public override Type DriverDebugUIType => null;
public override Type DriverUIType => null;
/// <inheritdoc/>
public override VariablePropertyBase VariablePropertys => null;
protected override IReadWrite _readWrite => null;
protected override UploadPropertyWithCache _uploadPropertyWithCache => _driverPropertys;
public override void Init(DeviceRunTime device)
{
base.Init(device);
device.DeviceVariableRunTimes = _globalDeviceData.AllVariables.Where(a => a.AlarmEnable).ToList();
CollectDevices = _globalDeviceData.CollectDevices.Where(a => a.DeviceVariableRunTimes.Any(a => a.AlarmEnable)).ToList();
}
/// <summary>
/// <inheritdoc/>
/// </summary>
/// <returns></returns>
public override bool IsConnected() => success;
/// <inheritdoc/>
public override string ToString()
{
return $" {nameof(SQLHisAlarm)}";
}
private TypeAdapterConfig _config;
protected override void Init(ISenderClient client = null)
{
base.Init(client);
_config = new TypeAdapterConfig();
_config.ForType<AlarmVariable, HistoryAlarm>()
.Map(dest => dest.Value, src => src.Value == null ? string.Empty : src.Value.ToString() ?? string.Empty)
.Map(dest => dest.Id, (src) =>
YitIdHelper.NextId());
var alarmWorker = BackgroundServiceUtil.GetBackgroundService<AlarmWorker>();
alarmWorker.OnAlarmChanged += AlarmWorker_OnAlarmChanged;
if (_uploadPropertyWithCache.CycleInterval <= 100) _uploadPropertyWithCache.CycleInterval = 100;
}
private void AlarmWorker_OnAlarmChanged(AlarmVariable alarmVariable)
{
if (!CurrentDevice.KeepRun)
return;
AddVariableQueue(alarmVariable.Adapt<HistoryAlarm>(_config ?? TypeAdapterConfig.GlobalSettings));
}
protected override async Task ProtectedBeforStartAsync(CancellationToken cancellationToken)
{
var db = GetDb();
db.CodeFirst.InitTables(typeof(HistoryAlarm));
await base.ProtectedBeforStartAsync(cancellationToken);
}
protected override async Task ProtectedExecuteAsync(CancellationToken cancellationToken)
{
//获取设备连接状态
if (IsConnected())
{
//更新设备活动时间
CurrentDevice.SetDeviceStatus(DateTimeExtensions.CurrentDateTime, 0);
}
else
{
//if (!IsUploadBase)
CurrentDevice.SetDeviceStatus(DateTimeExtensions.CurrentDateTime, 999);
}
CurrentDevice.SetDeviceStatus(DateTimeExtensions.CurrentDateTime, CurrentDevice.ErrorCount + 1);
var cacheItems = new List<CacheItem>();
var db = GetDb();
db.Ado.CancellationToken = cancellationToken;
{
try
{
var list = _alarmVariables.ToListWithDequeue();
if (list?.Count != 0)
{
var result = await InserableAsync(db, list, cancellationToken);
if (success != result.IsSuccess)
{
if (!result.IsSuccess)
LogMessage.Warning(result.ToString());
success = result.IsSuccess;
}
if (!result.IsSuccess)
{
AddCache(cacheItems, list);
}
}
}
catch (Exception ex)
{
LogMessage?.LogWarning(ex);
}
if (cacheItems.Count > 0)
CacheDb.Cache.Insert(cacheItems);
List<long> successIds = new();
try
{
var varList = CacheDb.Cache.Find(a => a.Type == varType, 0, _driverPropertys.CacheSendCount).ToList();//最大100w条
{
var item = varList.SelectMany(a => a.Value.FromJsonString<List<HistoryAlarm>>()).ToList();
if (item.Count != 0)
{
try
{
if (!cancellationToken.IsCancellationRequested)
{
var result = await InserableAsync(db, item, cancellationToken);
if (success != result.IsSuccess)
{
if (!result.IsSuccess)
LogMessage.Warning(result.ToString());
success = result.IsSuccess;
}
if (result.IsSuccess)
successIds.AddRange(varList.Select(a => a.Id));
}
}
catch (Exception ex)
{
LogMessage?.LogWarning(ex);
}
}
}
}
catch (Exception ex)
{
LogMessage?.LogWarning(ex);
}
if (successIds.Count > 0)
CacheDb.Cache.DeleteMany(a => successIds.Contains(a.Id));
}
await Delay(_driverPropertys.CycleInterval, cancellationToken);
}
}

View File

@@ -0,0 +1,222 @@
#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.Generic;
using Yitter.IdGenerator;
namespace ThingsGateway.Plugin.SQLHisAlarm;
/// <summary>
/// MqttClient
/// </summary>
public partial class SQLHisAlarm : UpLoadBaseWithCache
{
private const string devType = "dev";
private const string varType = "var";
private readonly SQLHisAlarmProperty _driverPropertys = new();
//private readonly SQLHisAlarmVariableProperty _variablePropertys = new();
private readonly EasyLock easyLock = new();
private ConcurrentQueue<HistoryAlarm> _alarmVariables = new();
private volatile bool success = true;
/// <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 void AddCache(List<CacheItem> cacheItems, IEnumerable<HistoryAlarm> dev)
{
var data = dev.ChunkBetter(_driverPropertys.CacheItemCount);
foreach (var item in data)
{
var cacheItem = new CacheItem()
{
Id = YitIdHelper.NextId(),
Type = varType,
Value = item.ToJsonString(),
};
cacheItems.Add(cacheItem);
}
}
private void AddCache(IEnumerable<IEnumerable<HistoryAlarm>> devData, List<CacheItem> cacheItems)
{
try
{
foreach (var dev in devData)
{
AddCache(cacheItems, dev);
}
}
catch (Exception ex)
{
LogMessage.LogWarning(ex, "缓存失败");
}
}
/// <summary>
/// 添加变量队列,超限后会入缓存
/// </summary>
/// <param name="variableData"></param>
private void AddVariableQueue(HistoryAlarm variableData)
{
//检测队列长度,超限存入缓存数据库
if (_alarmVariables.Count > _uploadPropertyWithCache.QueueMaxCount)
{
List<HistoryAlarm> list = null;
lock (_alarmVariables)
{
if (_alarmVariables.Count > _uploadPropertyWithCache.QueueMaxCount)
{
list = _alarmVariables.ToListWithDequeue();
}
}
if (list != null)
{
var devData = list.ChunkBetter(_uploadPropertyWithCache.SplitSize);
var cacheItems = new List<CacheItem>();
AddCache(devData, cacheItems);
if (cacheItems.Count > 0)
CacheDb.Cache.Insert(cacheItems);
}
}
_alarmVariables.Enqueue(variableData);
}
/// <summary>
/// 获取数据库链接
/// </summary>
/// <returns></returns>
private SqlSugarClient GetDb()
{
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.BigTextConnectStr,//连接字符串
DbType = _driverPropertys.DbType,//数据库类型
IsAutoCloseConnection = true, //不设成true要手动close
ConfigureExternalServices = configureExternalServices,
}
);
AopSetting(sqlSugarClient);//aop配置
return sqlSugarClient;
}
private async Task<OperResult> InserableAsync(SqlSugarClient db, List<HistoryAlarm> dbInserts, CancellationToken cancellationToken)
{
try
{
//.SplitTable()
var result = await db.Fastest<HistoryAlarm>().PageSize(50000).BulkCopyAsync(dbInserts);
//var result = await db.Insertable(dbInserts).SplitTable().ExecuteCommandAsync();
if (result > 0)
{
CurrentDevice.SetDeviceStatus(DateTimeExtensions.CurrentDateTime, 0);
LogMessage.Trace($"{FoundationConst.LogMessageHeader}主题:{nameof(HistoryAlarm)}");
}
return OperResult.CreateSuccessResult();
}
catch (Exception ex)
{
CurrentDevice.SetDeviceStatus(DateTimeExtensions.CurrentDateTime, 999);
return new(ex);
}
}
}

View File

@@ -0,0 +1,36 @@
#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.SQLHisAlarm;
/// <summary>
/// <inheritdoc/>
/// </summary>
public class SQLHisAlarmProperty : UploadPropertyWithCache
{
[DeviceProperty("数据库类型", "MySql/SqlServer")] public DbType DbType { get; set; } = DbType.MySql;
[DeviceProperty("链接字符串", "")] public string BigTextConnectStr { get; set; } = "server=localhost;Database=test;Uid=root;Pwd=111111;AllowLoadLocalInfile=true;";
public override bool IsAllVariable { get; set; } = true;
/// <summary>
/// 每次发送时合并的缓存值数量
/// </summary>
public virtual int CacheSendCount { get; set; } = 500;
/// <summary>
/// 每次添加缓存时,合并的变量值数量
/// </summary>
public virtual int CacheItemCount { get; set; } = 2000;
}

View File

@@ -0,0 +1,20 @@
#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.SQLHisAlarm;
/// <summary>
/// <inheritdoc/>
/// </summary>
//public class SQLHisAlarmVariableProperty : VariablePropertyBase
//{
//}

View File

@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
<Exec Command=" set dir=&quot;$(SolutionDir)Web\ThingsGateway.Web.Entry\bin\$(Configuration)\$(TargetFramework)\Plugins\$(AssemblyName)&quot;&#xD;&#xA; if not exist %25dir%25 md %25dir%25 &#xD;&#xA;copy &quot;$(TargetDir)*SQLHisAlarm*.dll&quot; %25dir%25&#xD;&#xA;&#xD;&#xA;&#xD;&#xA;&#xD;&#xA;" />
</Target>
</Project>

View File

@@ -36,7 +36,7 @@
<ItemGroup>
<ProjectReference Include="..\..\gateway\ThingsGateway.Gateway.Blazor\ThingsGateway.Gateway.Blazor.csproj" >
<ProjectReference Include="..\..\gateway\ThingsGateway.Gateway.Blazor\ThingsGateway.Gateway.Blazor.csproj">
<Private>false</Private>
<CopyLocalSatelliteAssemblies>false</CopyLocalSatelliteAssemblies>
<ExcludeAssets>runtime</ExcludeAssets>

View File

@@ -58,5 +58,5 @@ public class TDHistoryValue : STable
/// </summary>
[Description("变量值")]
[SugarColumn(Length = 18, DecimalDigits = 2)]
public double Value { get; set; }
public string Value { get; set; }
}

View File

@@ -16,8 +16,6 @@ using Mapster;
using Microsoft.Extensions.Logging;
using MQTTnet.Diagnostics;
using SqlSugar;
using ThingsGateway.Foundation.Extension.ConcurrentQueue;
@@ -28,7 +26,7 @@ namespace ThingsGateway.Plugin.TDengineDB;
/// <summary>
/// SQLDB
/// </summary>
public partial class TDengineDB : UpLoadBaseWithCache<DeviceData, TDHistoryValue>
public partial class TDengineDB : UpLoadBaseWithCacheT<DeviceData, TDHistoryValue>
{
protected override bool _device => false;
protected override bool _variable => true;
@@ -41,7 +39,7 @@ public partial class TDengineDB : UpLoadBaseWithCache<DeviceData, TDHistoryValue
public override VariablePropertyBase VariablePropertys => _variablePropertys;
protected override IReadWrite _readWrite => null;
protected override UploadPropertyWithCache _uploadPropertyWithCache => _driverPropertys;
protected override UploadPropertyWithCacheT _uploadPropertyWithCache => _driverPropertys;
/// <summary>
/// <inheritdoc/>
@@ -59,7 +57,7 @@ public partial class TDengineDB : UpLoadBaseWithCache<DeviceData, TDHistoryValue
{
_config = new TypeAdapterConfig();
_config.ForType<DeviceVariableRunTime, TDHistoryValue>()
.Map(dest => dest.Value, (src) => ValueReturn(src));
.Map(dest => dest.Value, src => src.Value == null ? string.Empty : src.Value.ToString() ?? string.Empty);
base.Init(client);
}

View File

@@ -22,7 +22,6 @@ using System.ComponentModel.DataAnnotations;
using System.Reflection;
using ThingsGateway.Foundation.Extension.Generic;
using ThingsGateway.Foundation.Extension.String;
using Yitter.IdGenerator;
@@ -31,7 +30,7 @@ namespace ThingsGateway.Plugin.TDengineDB;
/// <summary>
/// MqttClient
/// </summary>
public partial class TDengineDB : UpLoadBaseWithCache<DeviceData, TDHistoryValue>
public partial class TDengineDB : UpLoadBaseWithCacheT<DeviceData, TDHistoryValue>
{
private const string devType = "dev";
private const string varType = "var";
@@ -39,19 +38,6 @@ public partial class TDengineDB : UpLoadBaseWithCache<DeviceData, TDHistoryValue
private readonly TDengineDBVariableProperty _variablePropertys = new();
private volatile bool success = true;
private static object ValueReturn(DeviceVariableRunTime src)
{
var data = src.Value?.ToString()?.ToBool();
if (data != null)
{
return data;
}
else
{
return src.Value;
}
}
protected override void AddCache(List<CacheItem> cacheItems, IEnumerable<TDHistoryValue> dev)
{
var data = dev.ChunkBetter(_driverPropertys.CacheItemCount);

View File

@@ -17,7 +17,7 @@ namespace ThingsGateway.Plugin.TDengineDB;
/// <summary>
/// <inheritdoc/>
/// </summary>
public class TDengineDBProperty : UploadPropertyWithCache
public class TDengineDBProperty : UploadPropertyWithCacheT
{
public DbType DbType { get; set; } = DbType.TDengine;

View File

@@ -1,6 +1,6 @@
<Project>
<PropertyGroup>
<Version>4.0.0.0</Version>
<Version>4.0.0.5</Version>
<LangVersion>latest</LangVersion>
<ImplicitUsings>enable</ImplicitUsings>
<TargetFrameworks>net6.0;net8.0;</TargetFrameworks>
@@ -13,6 +13,4 @@
<SatelliteResourceLanguages>zh-Hans</SatelliteResourceLanguages>
</PropertyGroup>
</Project>

View File

@@ -54,20 +54,6 @@ public class Program
builder.Host.UseWindowsService();
builder.Host.UseSystemd();
#if AF2021
builder.WebHost.UseKestrel(
o =>
{
var config = Furion.App.GetConfig<ThingsGateway.Gateway.LK.MqttConfig>("MqttConfig", true);
if (config.Enable)
{
o.ListenAnyIP(config.Port, a => MQTTnet.AspNetCore.ConnectionBuilderExtensions.UseMqtt(a));
o.ListenAnyIP(config.WebSocketPort);
}
});
#endif
//Furion便利方法
builder.Inject();
var app = builder.Build();

Some files were not shown because too many files have changed in this diff Show More