Compare commits
	
		
			4 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					24bc60abf0 | ||
| 
						 | 
					31eee6b009 | ||
| 
						 | 
					c5da565a8f | ||
| 
						 | 
					947cd712e1 | 
@@ -1,6 +1,6 @@
 | 
				
			|||||||
<Project>
 | 
					<Project>
 | 
				
			||||||
	<PropertyGroup>
 | 
						<PropertyGroup>
 | 
				
			||||||
		<Version>3.0.0.2</Version>
 | 
							<Version>3.0.0.4</Version>
 | 
				
			||||||
		<LangVersion>latest</LangVersion>
 | 
							<LangVersion>latest</LangVersion>
 | 
				
			||||||
		<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
 | 
							<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
 | 
				
			||||||
		<Authors>Diego</Authors>
 | 
							<Authors>Diego</Authors>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -124,6 +124,15 @@ public partial class MainLayout
 | 
				
			|||||||
        "Title": "OPCUAClient"
 | 
					        "Title": "OPCUAClient"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    ]
 | 
					    ]
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    "Title": "Mqtt",
 | 
				
			||||||
 | 
					    "Children": [
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        "Href": "/MqttClient",
 | 
				
			||||||
 | 
					        "Title": "MqttClient"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -45,6 +45,13 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	<ItemGroup>
 | 
						<ItemGroup>
 | 
				
			||||||
		<Compile Include="..\..\Plugin\ThingsGateway.Plugin.DLT645\Page\DLT645_2007DebugPage.razor.cs" Link="Pages\DLT645\DLT645_2007DebugPage.razor.cs" />
 | 
							<Compile Include="..\..\Plugin\ThingsGateway.Plugin.DLT645\Page\DLT645_2007DebugPage.razor.cs" Link="Pages\DLT645\DLT645_2007DebugPage.razor.cs" />
 | 
				
			||||||
 | 
							<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Mqtt\MqttRpcNameVaueWithId.cs" Link="Pages\Mqtt\MqttRpcNameVaueWithId.cs" />
 | 
				
			||||||
 | 
							<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Mqtt\Page\MqttClientDebugPage.razor.cs" Link="Pages\Mqtt\MqttClientDebugPage.razor.cs" />
 | 
				
			||||||
 | 
							<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Mqtt\Page\MqttClientPage.razor.cs" Link="Pages\Mqtt\MqttClientPage.razor.cs" />
 | 
				
			||||||
 | 
							<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Mqtt\PrivateLogger.cs" Link="Pages\Mqtt\PrivateLogger.cs" />
 | 
				
			||||||
 | 
							<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Mqtt\RpcClass\MqttRpcClient.cs" Link="Pages\Mqtt\MqttRpcClient.cs" />
 | 
				
			||||||
 | 
							<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Mqtt\RpcClass\MqttRpcClientExtensions.cs" Link="Pages\Mqtt\MqttRpcClientExtensions.cs" />
 | 
				
			||||||
 | 
							<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Mqtt\RpcClass\MqttRpcTopicPair.cs" Link="Pages\Mqtt\MqttRpcTopicPair.cs" />
 | 
				
			||||||
		<Content Include="..\..\Plugin\ThingsGateway.Plugin.DLT645\Page\DLT645_2007DebugPage.razor" Link="Pages\DLT645\DLT645_2007DebugPage.razor" />
 | 
							<Content Include="..\..\Plugin\ThingsGateway.Plugin.DLT645\Page\DLT645_2007DebugPage.razor" Link="Pages\DLT645\DLT645_2007DebugPage.razor" />
 | 
				
			||||||
		<Compile Include="..\..\Plugin\ThingsGateway.Plugin.DLT645\Page\DLT645_2007OverTcpDebugPage.razor.cs" Link="Pages\DLT645\DLT645_2007OverTcpDebugPage.razor.cs" />
 | 
							<Compile Include="..\..\Plugin\ThingsGateway.Plugin.DLT645\Page\DLT645_2007OverTcpDebugPage.razor.cs" Link="Pages\DLT645\DLT645_2007OverTcpDebugPage.razor.cs" />
 | 
				
			||||||
		<Content Include="..\..\Plugin\ThingsGateway.Plugin.DLT645\Page\DLT645_2007OverTcpDebugPage.razor" Link="Pages\DLT645\DLT645_2007OverTcpDebugPage.razor" />
 | 
							<Content Include="..\..\Plugin\ThingsGateway.Plugin.DLT645\Page\DLT645_2007OverTcpDebugPage.razor" Link="Pages\DLT645\DLT645_2007OverTcpDebugPage.razor" />
 | 
				
			||||||
@@ -117,5 +124,17 @@
 | 
				
			|||||||
	</ItemGroup>
 | 
						</ItemGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<ItemGroup>
 | 
				
			||||||
 | 
						  <Folder Include="Pages\Mqtt\" />
 | 
				
			||||||
 | 
						</ItemGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<ItemGroup>
 | 
				
			||||||
 | 
						  <Content Include="..\..\Plugin\ThingsGateway.Plugin.Mqtt\Page\MqttClientDebugPage.razor" Link="Pages\Mqtt\MqttClientDebugPage.razor" />
 | 
				
			||||||
 | 
						  <Content Include="..\..\Plugin\ThingsGateway.Plugin.Mqtt\Page\MqttClientPage.razor" Link="Pages\Mqtt\MqttClientPage.razor" />
 | 
				
			||||||
 | 
							<PackageReference Include="MQTTnet" Version="4.3.1.873" />
 | 
				
			||||||
 | 
						</ItemGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
</Project>
 | 
					</Project>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
<Project>
 | 
					<Project>
 | 
				
			||||||
	<PropertyGroup>
 | 
						<PropertyGroup>
 | 
				
			||||||
		<Version>3.0.0.2</Version>
 | 
							<Version>3.0.0.4</Version>
 | 
				
			||||||
		<GenerateDocumentationFile>True</GenerateDocumentationFile>
 | 
							<GenerateDocumentationFile>True</GenerateDocumentationFile>
 | 
				
			||||||
		<LangVersion>latest</LangVersion>
 | 
							<LangVersion>latest</LangVersion>
 | 
				
			||||||
		<TargetFrameworks>net45;netstandard2.0;net6.0;net7.0</TargetFrameworks>
 | 
							<TargetFrameworks>net45;netstandard2.0;net6.0;net7.0</TargetFrameworks>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -440,9 +440,7 @@ public class TcpClientBase : BaseSocket, ITcpClient
 | 
				
			|||||||
            {
 | 
					            {
 | 
				
			||||||
                throw new TimeoutException("连接超时");
 | 
					                throw new TimeoutException("连接超时");
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
            success(socket);
 | 
					            success(socket);
 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
            using CancellationTokenSource cancellationTokenSource = new();
 | 
					            using CancellationTokenSource cancellationTokenSource = new();
 | 
				
			||||||
@@ -465,11 +463,10 @@ public class TcpClientBase : BaseSocket, ITcpClient
 | 
				
			|||||||
            else
 | 
					            else
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                socket?.SafeDispose();
 | 
					                socket?.SafeDispose();
 | 
				
			||||||
                socket.Close();
 | 
					                throw new TimeoutException("连接超时");
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        finally
 | 
					        finally
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
<Project>
 | 
					<Project>
 | 
				
			||||||
	<PropertyGroup>
 | 
						<PropertyGroup>
 | 
				
			||||||
		<Version>3.0.0.2</Version>
 | 
							<Version>3.0.0.4</Version>
 | 
				
			||||||
		<LangVersion>latest</LangVersion>
 | 
							<LangVersion>latest</LangVersion>
 | 
				
			||||||
		<ImplicitUsings>enable</ImplicitUsings>
 | 
							<ImplicitUsings>enable</ImplicitUsings>
 | 
				
			||||||
		<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
 | 
							<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
 | 
				
			||||||
@@ -11,7 +11,6 @@
 | 
				
			|||||||
		<SignAssembly>True</SignAssembly>
 | 
							<SignAssembly>True</SignAssembly>
 | 
				
			||||||
		<DelaySign>False</DelaySign>
 | 
							<DelaySign>False</DelaySign>
 | 
				
			||||||
		<SatelliteResourceLanguages>zh-Hans</SatelliteResourceLanguages>
 | 
							<SatelliteResourceLanguages>zh-Hans</SatelliteResourceLanguages>
 | 
				
			||||||
		<GenerateDocumentationFile>True</GenerateDocumentationFile>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	</PropertyGroup>
 | 
						</PropertyGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,6 +10,9 @@
 | 
				
			|||||||
//------------------------------------------------------------------------------
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
#endregion
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					global using ThingsGateway.Components;
 | 
				
			||||||
global using ThingsGateway.Foundation;
 | 
					global using ThingsGateway.Foundation;
 | 
				
			||||||
 | 
					global using ThingsGateway.Foundation.Serial;
 | 
				
			||||||
 | 
					global using ThingsGateway.Foundation.Sockets;
 | 
				
			||||||
global using ThingsGateway.Gateway.Application;
 | 
					global using ThingsGateway.Gateway.Application;
 | 
				
			||||||
global using ThingsGateway.Gateway.Core;
 | 
					global using ThingsGateway.Gateway.Core;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,6 +22,7 @@ using MQTTnet.Client;
 | 
				
			|||||||
using System.Collections.Concurrent;
 | 
					using System.Collections.Concurrent;
 | 
				
			||||||
using System.Text;
 | 
					using System.Text;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using ThingsGateway.Foundation.Demo;
 | 
				
			||||||
using ThingsGateway.Foundation.Extension.ConcurrentQueue;
 | 
					using ThingsGateway.Foundation.Extension.ConcurrentQueue;
 | 
				
			||||||
using ThingsGateway.Foundation.Extension.Generic;
 | 
					using ThingsGateway.Foundation.Extension.Generic;
 | 
				
			||||||
using ThingsGateway.Foundation.Extension.String;
 | 
					using ThingsGateway.Foundation.Extension.String;
 | 
				
			||||||
@@ -55,7 +56,7 @@ public class MqttClient : UpLoadBase
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    private TimerTick exVariableTimerTick;
 | 
					    private TimerTick exVariableTimerTick;
 | 
				
			||||||
    /// <inheritdoc/>
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
    public override Type DriverDebugUIType => null;
 | 
					    public override Type DriverDebugUIType => typeof(MqttClientDebugPage);
 | 
				
			||||||
    /// <inheritdoc/>
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
    public override UpDriverPropertyBase DriverPropertys => driverPropertys;
 | 
					    public override UpDriverPropertyBase DriverPropertys => driverPropertys;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,6 +10,10 @@
 | 
				
			|||||||
//------------------------------------------------------------------------------
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
#endregion
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using ThingsGateway.Foundation;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ThingsGateway.Plugin.Mqtt;
 | 
					namespace ThingsGateway.Plugin.Mqtt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// <summary>
 | 
					/// <summary>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,85 @@
 | 
				
			|||||||
 | 
					@*
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					//  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
 | 
				
			||||||
 | 
					//  此代码版权(除特别声明外的代码)归作者本人Diego所有
 | 
				
			||||||
 | 
					//  源代码使用协议遵循本仓库的开源协议及附加协议
 | 
				
			||||||
 | 
					//  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  使用文档:https://diego2098.gitee.io/thingsgateway-docs/
 | 
				
			||||||
 | 
					//  QQ群:605534569
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					*@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@page "/MqttClient"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@namespace ThingsGateway.Foundation.Demo
 | 
				
			||||||
 | 
					@using BlazorComponent;
 | 
				
			||||||
 | 
					@using Microsoft.AspNetCore.Components.Web;
 | 
				
			||||||
 | 
					@using Masa.Blazor.Presets;
 | 
				
			||||||
 | 
					@using Microsoft.JSInterop;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@using ThingsGateway.Foundation;
 | 
				
			||||||
 | 
					@using ThingsGateway.Foundation.Extension;
 | 
				
			||||||
 | 
					@using Masa.Blazor
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<MqttClientPage @ref=mqttClientPage></MqttClientPage>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<DriverDebugUIPage @ref=driverDebugUIPage Sections="_sections" ShowDefaultOtherContent=false>
 | 
				
			||||||
 | 
					    <ReadWriteContent>
 | 
				
			||||||
 | 
					        <div class="my-1 py-1">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <MTextarea Class="mx-1 my-1" Label="订阅主题" Dense Outlined HideDetails="@("auto")" @bind-Value=@driverDebugUIPage.Address />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					             <MButton Class="mx-1 my-1" Color="primary" OnClick="SubscribeAsync">
 | 
				
			||||||
 | 
					                添加
 | 
				
			||||||
 | 
					            </MButton>
 | 
				
			||||||
 | 
					             <MButton Class="mx-1 my-1" Color="primary" OnClick="UnsubscribeAsync">
 | 
				
			||||||
 | 
					                移除
 | 
				
			||||||
 | 
					            </MButton>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					             <MTextarea Class="mx-1 my-1" Label="发布主题" Dense Outlined HideDetails="@("auto")" @bind-Value=@PublishTopic />
 | 
				
			||||||
 | 
					             <MTextarea Class="mx-1 my-1" Label="发布内容" Dense Outlined HideDetails="@("auto")" @bind-Value=@PublishValue />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					             <MButton Class="mx-1 my-1" Color="primary" OnClick="PublishAsync">
 | 
				
			||||||
 | 
					                 发布
 | 
				
			||||||
 | 
					             </MButton>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					             <MSubheader Class="mt-4 font-weight-black"> Rpc  </MSubheader>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					             <MTextarea Class="mx-1 mt-3 my-1" Label="Rpc主题" Dense Outlined HideDetails="@("auto")" @bind-Value=@MqttRpcTopicPair.RequestTopic />
 | 
				
			||||||
 | 
					             <MTextarea Class="mx-1 mt-3 my-1" Label="Rpc返回主题" Dense Outlined HideDetails="@("auto")" @bind-Value=@MqttRpcTopicPair.ResponseTopic />
 | 
				
			||||||
 | 
					             <MTextarea Class="mx-1 mt-3 my-1" Label="Rpc内容" Dense Outlined HideDetails="@("auto")" @bind-Value=@driverDebugUIPage.WriteValue />
 | 
				
			||||||
 | 
					             <MButton Class="mx-1 my-1" Color="primary" OnClick="RpcExecuteAsync">
 | 
				
			||||||
 | 
					                执行
 | 
				
			||||||
 | 
					            </MButton>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <MCol Class="my-1 py-1">
 | 
				
			||||||
 | 
					            <MRow NoGutters>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            </MRow>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        </MCol>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    </ReadWriteContent>
 | 
				
			||||||
 | 
					</DriverDebugUIPage>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@code {
 | 
				
			||||||
 | 
					    private readonly List<(string Code, string Language)> _sections = new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,154 @@
 | 
				
			|||||||
 | 
					#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 Masa.Blazor;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using Microsoft.AspNetCore.Components;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using MQTTnet;
 | 
				
			||||||
 | 
					using MQTTnet.Extensions.Rpc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Text;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using ThingsGateway.Plugin.Mqtt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace ThingsGateway.Foundation.Demo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// <summary>
 | 
				
			||||||
 | 
					/// MqttClientDebugPage
 | 
				
			||||||
 | 
					/// </summary>
 | 
				
			||||||
 | 
					public partial class MqttClientDebugPage : IDisposable
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    private DriverDebugUIPage driverDebugUIPage;
 | 
				
			||||||
 | 
					    private MqttClientPage mqttClientPage;
 | 
				
			||||||
 | 
					    [Inject]
 | 
				
			||||||
 | 
					    private InitTimezone InitTimezone { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    [Inject]
 | 
				
			||||||
 | 
					    IPopupService PopupService { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public void Dispose()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        mqttClientPage.SafeDispose();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    protected override void OnAfterRender(bool firstRender)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (firstRender)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (mqttClientPage != null)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                mqttClientPage.LogAction = driverDebugUIPage.LogOut;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            //初始化
 | 
				
			||||||
 | 
					            driverDebugUIPage.Address = "ThingsGateway/Variable";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            driverDebugUIPage.WriteValue = new MqttRpcNameVaueWithId()
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                RpcId = Guid.NewGuid().ToString(),
 | 
				
			||||||
 | 
					                WriteInfos = new Dictionary<string, string>()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    { "tag1", "123" }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					            }.ToJsonString();
 | 
				
			||||||
 | 
					            ;
 | 
				
			||||||
 | 
					            mqttClientPage.IP = "127.0.0.1";
 | 
				
			||||||
 | 
					            mqttClientPage.Port = 1883;
 | 
				
			||||||
 | 
					            mqttClientPage.UserName = "admin";
 | 
				
			||||||
 | 
					            mqttClientPage.Password = "111111";
 | 
				
			||||||
 | 
					            mqttClientPage.StateHasChangedAsync();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            //载入配置
 | 
				
			||||||
 | 
					            StateHasChanged();
 | 
				
			||||||
 | 
					            driverDebugUIPage.Sections.Clear();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        base.OnAfterRender(firstRender);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private async Task SubscribeAsync()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        try
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var mqttSubscribeOptions = mqttClientPage.MqttFactory.CreateSubscribeOptionsBuilder()
 | 
				
			||||||
 | 
					.WithTopicFilter(
 | 
				
			||||||
 | 
					f =>
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    f.WithTopic(driverDebugUIPage.Address);
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					.Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            await mqttClientPage.MqttClient.SubscribeAsync(mqttSubscribeOptions, CancellationToken.None);
 | 
				
			||||||
 | 
					            driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Information, DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(driverDebugUIPage.InitTimezone.TimezoneOffset) + " - " + $"订阅{driverDebugUIPage.Address}成功"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch (Exception ex)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Error, DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(driverDebugUIPage.InitTimezone.TimezoneOffset) + " - " + ex.Message));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    private async Task UnsubscribeAsync()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        try
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var mqttSubscribeOptions = mqttClientPage.MqttFactory.CreateUnsubscribeOptionsBuilder()
 | 
				
			||||||
 | 
					.WithTopicFilter(driverDebugUIPage.Address)
 | 
				
			||||||
 | 
					.Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            await mqttClientPage.MqttClient.UnsubscribeAsync(mqttSubscribeOptions, CancellationToken.None);
 | 
				
			||||||
 | 
					            driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Information, DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(driverDebugUIPage.InitTimezone.TimezoneOffset) + " - " + $"取消订阅{driverDebugUIPage.Address}成功"));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch (Exception ex)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Error, DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(driverDebugUIPage.InitTimezone.TimezoneOffset) + " - " + ex.Message));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    string PublishTopic;
 | 
				
			||||||
 | 
					    string PublishValue;
 | 
				
			||||||
 | 
					    private async Task PublishAsync()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        try
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var devMessage = new MqttApplicationMessageBuilder()
 | 
				
			||||||
 | 
					.WithTopic($"{PublishTopic}")
 | 
				
			||||||
 | 
					.WithPayload(PublishValue).Build();
 | 
				
			||||||
 | 
					            await mqttClientPage.MqttClient.PublishAsync(devMessage, CancellationToken.None);
 | 
				
			||||||
 | 
					            driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Information, DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(driverDebugUIPage.InitTimezone.TimezoneOffset) + " - " + $"发布{PublishTopic}成功"));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch (Exception ex)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Error, DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(driverDebugUIPage.InitTimezone.TimezoneOffset) + " - " + ex.Message));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    MqttRpcTopicPair MqttRpcTopicPair = new() { RequestTopic = "ThingsGateway/RpcWrite", ResponseTopic = "ThingsGateway/RpcSub" };
 | 
				
			||||||
 | 
					    private async Task RpcExecuteAsync()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        try
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            using MqttRpcClient mqttRpcClient = new(mqttClientPage.MqttClient);
 | 
				
			||||||
 | 
					            var data = await mqttRpcClient.ExecuteAsync(MqttRpcTopicPair, driverDebugUIPage.WriteValue, MQTTnet.Protocol.MqttQualityOfServiceLevel.AtMostOnce, TimeSpan.FromSeconds(10));
 | 
				
			||||||
 | 
					            var str = Encoding.UTF8.GetString(data);
 | 
				
			||||||
 | 
					            driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Information, DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(driverDebugUIPage.InitTimezone.TimezoneOffset) + " - " + str));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch (Exception ex)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Error, DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(driverDebugUIPage.InitTimezone.TimezoneOffset) + " - " + ex.Message));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,42 @@
 | 
				
			|||||||
 | 
					@*
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					//  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
 | 
				
			||||||
 | 
					//  此代码版权(除特别声明外的代码)归作者本人Diego所有
 | 
				
			||||||
 | 
					//  源代码使用协议遵循本仓库的开源协议及附加协议
 | 
				
			||||||
 | 
					//  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  使用文档:https://diego2098.gitee.io/thingsgateway-docs/
 | 
				
			||||||
 | 
					//  QQ群:605534569
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					*@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@namespace ThingsGateway.Foundation.Demo
 | 
				
			||||||
 | 
					@using BlazorComponent;
 | 
				
			||||||
 | 
					@using Microsoft.AspNetCore.Components.Web;
 | 
				
			||||||
 | 
					@using System.IO.Ports;
 | 
				
			||||||
 | 
					@using System.Collections.Concurrent;
 | 
				
			||||||
 | 
					@using ThingsGateway.Foundation;
 | 
				
			||||||
 | 
					@using Masa.Blazor
 | 
				
			||||||
 | 
					@implements IDisposable
 | 
				
			||||||
 | 
					<MCard Elevation="1" Rounded="false" Class="pa-2" Style="width:100%">
 | 
				
			||||||
 | 
					    <div class="mb-4">设备配置</div>
 | 
				
			||||||
 | 
					    <MRow Justify="JustifyTypes.Start" Align="AlignTypes.Center">
 | 
				
			||||||
 | 
					        <MTextField Class="ma-1" Label=IP Dense Outlined HideDetails="@("auto")" @bind-Value=@IP />
 | 
				
			||||||
 | 
					        <MTextField Class="ma-1" Label=端口 Dense Outlined HideDetails="@("auto")" @bind-Value=@Port />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <MTextField Class="ma-1" Label=ID Dense Outlined HideDetails="@("auto")" @bind-Value=@ConnectId />
 | 
				
			||||||
 | 
					        <MTextField Class="ma-1" Label=用户 Dense Outlined HideDetails="@("auto")" @bind-Value=@UserName />
 | 
				
			||||||
 | 
					        <MTextField Class="ma-1" Label=密码 Dense Outlined HideDetails="@("auto")" @bind-Value=@Password />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <MButton Class="ma-1" OnClick=@Connect Color="primary">
 | 
				
			||||||
 | 
					            连接
 | 
				
			||||||
 | 
					        </MButton>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <MButton Class="ma-1" OnClick=@DisConnect Color="red">
 | 
				
			||||||
 | 
					            断开
 | 
				
			||||||
 | 
					        </MButton>
 | 
				
			||||||
 | 
					    </MRow>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</MCard>
 | 
				
			||||||
@@ -0,0 +1,119 @@
 | 
				
			|||||||
 | 
					#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 MQTTnet;
 | 
				
			||||||
 | 
					using MQTTnet.Client;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using System.Text;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using ThingsGateway.Plugin.Mqtt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace ThingsGateway.Foundation.Demo;
 | 
				
			||||||
 | 
					/// <summary>
 | 
				
			||||||
 | 
					/// MqttClientPage
 | 
				
			||||||
 | 
					/// </summary>
 | 
				
			||||||
 | 
					public partial class MqttClientPage
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 日志输出
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public Action<LogLevel, object, string, Exception> LogAction;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// OPC
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public IMqttClient MqttClient;
 | 
				
			||||||
 | 
					    public MqttClientOptions MqttClientOptions;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public MqttFactory MqttFactory;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public string ConnectId;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public string IP;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public string Password;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public int Port;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public string UserName;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public void Dispose()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        MqttClient.SafeDispose();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    protected override void OnInitialized()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        MqttFactory = new MqttFactory(new PrivateLogger(new EasyLogger(LogAction) { LogLevel = LogLevel.Trace }));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        MqttClient = MqttFactory.CreateMqttClient();
 | 
				
			||||||
 | 
					        MqttClient.ApplicationMessageReceivedAsync += MqttClient_ApplicationMessageReceivedAsync;
 | 
				
			||||||
 | 
					        base.OnInitialized();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private async Task Connect()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        try
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            await MqttClient.DisconnectAsync();
 | 
				
			||||||
 | 
					            await GetMqttClient();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch (Exception ex)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            LogAction?.Invoke(LogLevel.Error, null, null, ex);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private async Task DisConnect()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        try
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            await MqttClient.DisconnectAsync();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch (Exception ex)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            LogAction?.Invoke(LogLevel.Error, null, null, ex);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private async Task<IMqttClient> GetMqttClient()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        //载入配置
 | 
				
			||||||
 | 
					        MqttClientOptions = MqttFactory.CreateClientOptionsBuilder()
 | 
				
			||||||
 | 
					   .WithClientId(ConnectId)
 | 
				
			||||||
 | 
					   .WithCredentials(UserName, Password)//账密
 | 
				
			||||||
 | 
					   .WithTcpServer(IP, Port)//服务器
 | 
				
			||||||
 | 
					   .WithCleanSession(true)
 | 
				
			||||||
 | 
					   .WithKeepAlivePeriod(TimeSpan.FromSeconds(120.0))
 | 
				
			||||||
 | 
					   .WithoutThrowOnNonSuccessfulConnectResponse()
 | 
				
			||||||
 | 
					   .Build();
 | 
				
			||||||
 | 
					        await MqttClient.ConnectAsync(MqttClientOptions);
 | 
				
			||||||
 | 
					        return MqttClient;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void LogOut(byte logLevel, object source, string message, Exception exception) => LogAction?.Invoke((LogLevel)logLevel, source, message, exception);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private Task MqttClient_ApplicationMessageReceivedAsync(MqttApplicationMessageReceivedEventArgs args)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LogAction?.Invoke(LogLevel.Info, this, $"[{args.ApplicationMessage.Topic}]:{Encoding.UTF8.GetString(args.ApplicationMessage.PayloadSegment)}", null);
 | 
				
			||||||
 | 
					        return Task.CompletedTask;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public Task StateHasChangedAsync()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return InvokeAsync(StateHasChanged);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -12,6 +12,8 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
using MQTTnet.Diagnostics;
 | 
					using MQTTnet.Diagnostics;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using ThingsGateway.Foundation;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ThingsGateway.Plugin.Mqtt
 | 
					namespace ThingsGateway.Plugin.Mqtt
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    internal class PrivateLogger : IMqttNetLogger
 | 
					    internal class PrivateLogger : IMqttNetLogger
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,147 @@
 | 
				
			|||||||
 | 
					#region copyright
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					//  <20>˴<EFBFBD><CBB4><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><C8A8><EFBFBD><EFBFBD>Ϊȫ<CEAA>ļ<EFBFBD><C4BC><EFBFBD><EFBFBD>ǣ<EFBFBD><C7A3><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><D4AD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><D8B1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><C2B7>ֶ<EFBFBD><D6B6><EFBFBD><EFBFBD><EFBFBD>
 | 
				
			||||||
 | 
					//  <20>˴<EFBFBD><CBB4><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><C8A8><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><D8B1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><C4B4>룩<EFBFBD><EBA3A9><EFBFBD><EFBFBD><EFBFBD>߱<EFBFBD><DFB1><EFBFBD>Diego<67><6F><EFBFBD><EFBFBD>
 | 
				
			||||||
 | 
					//  Դ<><D4B4><EFBFBD><EFBFBD>ʹ<EFBFBD><CAB9>Э<EFBFBD><D0AD><EFBFBD><EFBFBD>ѭ<EFBFBD><D1AD><EFBFBD>ֿ<EFBFBD><D6BF>Ŀ<EFBFBD>ԴЭ<D4B4>鼰<EFBFBD><E9BCB0><EFBFBD><EFBFBD>Э<EFBFBD><D0AD>
 | 
				
			||||||
 | 
					//  GiteeԴ<65><D4B4><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://gitee.com/diego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  GithubԴ<62><D4B4><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  ʹ<><CAB9><EFBFBD>ĵ<EFBFBD><C4B5><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/
 | 
				
			||||||
 | 
					//  QQȺ<51><C8BA>605534569
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Licensed to the .NET Foundation under one or more agreements.
 | 
				
			||||||
 | 
					// The .NET Foundation licenses this file to you under the MIT license.
 | 
				
			||||||
 | 
					// See the LICENSE file in the project root for more information.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using MQTTnet.Client;
 | 
				
			||||||
 | 
					using MQTTnet.Exceptions;
 | 
				
			||||||
 | 
					using MQTTnet.Formatter;
 | 
				
			||||||
 | 
					using MQTTnet.Internal;
 | 
				
			||||||
 | 
					using MQTTnet.Protocol;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using System.Collections.Concurrent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace MQTTnet.Extensions.Rpc
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public sealed class MqttRpcClient : IDisposable
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        readonly IMqttClient _mqttClient;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        readonly ConcurrentDictionary<string, AsyncTaskCompletionSource<byte[]>> _waitingCalls = new ConcurrentDictionary<string, AsyncTaskCompletionSource<byte[]>>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public MqttRpcClient(IMqttClient mqttClient)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _mqttClient = mqttClient ?? throw new ArgumentNullException(nameof(mqttClient));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            _mqttClient.ApplicationMessageReceivedAsync += HandleApplicationMessageReceivedAsync;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public void Dispose()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _mqttClient.ApplicationMessageReceivedAsync -= HandleApplicationMessageReceivedAsync;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            foreach (var tcs in _waitingCalls)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                tcs.Value.TrySetCanceled();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            _waitingCalls.Clear();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public async Task<byte[]> ExecuteAsync(MqttRpcTopicPair mqttRpcTopicPair, byte[] payload, MqttQualityOfServiceLevel qualityOfServiceLevel, TimeSpan timeout)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            using var timeoutToken = new CancellationTokenSource(timeout);
 | 
				
			||||||
 | 
					            try
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                return await ExecuteAsync(mqttRpcTopicPair, payload, qualityOfServiceLevel, timeoutToken.Token).ConfigureAwait(false);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            catch (OperationCanceledException exception)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if (timeoutToken.IsCancellationRequested)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    throw new MqttCommunicationTimedOutException(exception);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                throw;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public async Task<byte[]> ExecuteAsync(MqttRpcTopicPair mqttRpcTopicPair, byte[] payload, MqttQualityOfServiceLevel qualityOfServiceLevel, CancellationToken cancellationToken = default)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (mqttRpcTopicPair == null)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                throw new ArgumentNullException(nameof(mqttRpcTopicPair));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var requestTopic = mqttRpcTopicPair.RequestTopic;
 | 
				
			||||||
 | 
					            var responseTopic = mqttRpcTopicPair.ResponseTopic;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (string.IsNullOrWhiteSpace(requestTopic))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                throw new MqttProtocolViolationException("RPC request topic is empty.");
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (string.IsNullOrWhiteSpace(responseTopic))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                throw new MqttProtocolViolationException("RPC response topic is empty.");
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var requestMessageBuilder = new MqttApplicationMessageBuilder().WithTopic(requestTopic).WithPayload(payload).WithQualityOfServiceLevel(qualityOfServiceLevel);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (_mqttClient.Options.ProtocolVersion == MqttProtocolVersion.V500)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                requestMessageBuilder.WithResponseTopic(responseTopic);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var requestMessage = requestMessageBuilder.Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            try
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var awaitable = new AsyncTaskCompletionSource<byte[]>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (!_waitingCalls.TryAdd(responseTopic, awaitable))
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    throw new InvalidOperationException();
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                var subscribeOptions = new MqttClientSubscribeOptionsBuilder().WithTopicFilter(responseTopic, qualityOfServiceLevel).Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                await _mqttClient.SubscribeAsync(subscribeOptions, cancellationToken).ConfigureAwait(false);
 | 
				
			||||||
 | 
					                await _mqttClient.PublishAsync(requestMessage, cancellationToken).ConfigureAwait(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                using (cancellationToken.Register(
 | 
				
			||||||
 | 
					                           () =>
 | 
				
			||||||
 | 
					                           {
 | 
				
			||||||
 | 
					                               awaitable.TrySetCanceled();
 | 
				
			||||||
 | 
					                           }))
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    return await awaitable.Task.ConfigureAwait(false);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            finally
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                _waitingCalls.TryRemove(responseTopic, out _);
 | 
				
			||||||
 | 
					                await _mqttClient.UnsubscribeAsync(responseTopic, CancellationToken.None).ConfigureAwait(false);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Task HandleApplicationMessageReceivedAsync(MqttApplicationMessageReceivedEventArgs eventArgs)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (!_waitingCalls.TryRemove(eventArgs.ApplicationMessage.Topic, out var awaitable))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                return CompletedTask.Instance;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var payloadBuffer = eventArgs.ApplicationMessage.PayloadSegment.ToArray();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            awaitable.TrySetResult(payloadBuffer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Set this message to handled to that other code can avoid execution etc.
 | 
				
			||||||
 | 
					            eventArgs.IsHandled = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return CompletedTask.Instance;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,34 @@
 | 
				
			|||||||
 | 
					#region copyright
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					//  <20>˴<EFBFBD><CBB4><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><C8A8><EFBFBD><EFBFBD>Ϊȫ<CEAA>ļ<EFBFBD><C4BC><EFBFBD><EFBFBD>ǣ<EFBFBD><C7A3><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><D4AD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><D8B1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><C2B7>ֶ<EFBFBD><D6B6><EFBFBD><EFBFBD><EFBFBD>
 | 
				
			||||||
 | 
					//  <20>˴<EFBFBD><CBB4><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><C8A8><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><D8B1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><C4B4>룩<EFBFBD><EBA3A9><EFBFBD><EFBFBD><EFBFBD>߱<EFBFBD><DFB1><EFBFBD>Diego<67><6F><EFBFBD><EFBFBD>
 | 
				
			||||||
 | 
					//  Դ<><D4B4><EFBFBD><EFBFBD>ʹ<EFBFBD><CAB9>Э<EFBFBD><D0AD><EFBFBD><EFBFBD>ѭ<EFBFBD><D1AD><EFBFBD>ֿ<EFBFBD><D6BF>Ŀ<EFBFBD>ԴЭ<D4B4>鼰<EFBFBD><E9BCB0><EFBFBD><EFBFBD>Э<EFBFBD><D0AD>
 | 
				
			||||||
 | 
					//  GiteeԴ<65><D4B4><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://gitee.com/diego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  GithubԴ<62><D4B4><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  ʹ<><CAB9><EFBFBD>ĵ<EFBFBD><C4B5><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/
 | 
				
			||||||
 | 
					//  QQȺ<51><C8BA>605534569
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Licensed to the .NET Foundation under one or more agreements.
 | 
				
			||||||
 | 
					// The .NET Foundation licenses this file to you under the MIT license.
 | 
				
			||||||
 | 
					// See the LICENSE file in the project root for more information.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using MQTTnet.Protocol;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using System.Text;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace MQTTnet.Extensions.Rpc
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public static class MqttRpcClientExtensions
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public static Task<byte[]> ExecuteAsync(this MqttRpcClient client, MqttRpcTopicPair mqttRpcTopicPair, string payload, MqttQualityOfServiceLevel qualityOfServiceLevel, TimeSpan timeout)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (client == null) throw new ArgumentNullException(nameof(client));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var buffer = Encoding.UTF8.GetBytes(payload ?? string.Empty);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return client.ExecuteAsync(mqttRpcTopicPair, buffer, qualityOfServiceLevel, timeout);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,25 @@
 | 
				
			|||||||
 | 
					#region copyright
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					//  <20>˴<EFBFBD><CBB4><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><C8A8><EFBFBD><EFBFBD>Ϊȫ<CEAA>ļ<EFBFBD><C4BC><EFBFBD><EFBFBD>ǣ<EFBFBD><C7A3><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><D4AD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><D8B1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><C2B7>ֶ<EFBFBD><D6B6><EFBFBD><EFBFBD><EFBFBD>
 | 
				
			||||||
 | 
					//  <20>˴<EFBFBD><CBB4><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><C8A8><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><D8B1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><C4B4>룩<EFBFBD><EBA3A9><EFBFBD><EFBFBD><EFBFBD>߱<EFBFBD><DFB1><EFBFBD>Diego<67><6F><EFBFBD><EFBFBD>
 | 
				
			||||||
 | 
					//  Դ<><D4B4><EFBFBD><EFBFBD>ʹ<EFBFBD><CAB9>Э<EFBFBD><D0AD><EFBFBD><EFBFBD>ѭ<EFBFBD><D1AD><EFBFBD>ֿ<EFBFBD><D6BF>Ŀ<EFBFBD>ԴЭ<D4B4>鼰<EFBFBD><E9BCB0><EFBFBD><EFBFBD>Э<EFBFBD><D0AD>
 | 
				
			||||||
 | 
					//  GiteeԴ<65><D4B4><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://gitee.com/diego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  GithubԴ<62><D4B4><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  ʹ<><CAB9><EFBFBD>ĵ<EFBFBD><C4B5><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/
 | 
				
			||||||
 | 
					//  QQȺ<51><C8BA>605534569
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Licensed to the .NET Foundation under one or more agreements.
 | 
				
			||||||
 | 
					// The .NET Foundation licenses this file to you under the MIT license.
 | 
				
			||||||
 | 
					// See the LICENSE file in the project root for more information.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace MQTTnet.Extensions.Rpc
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public sealed class MqttRpcTopicPair
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public string RequestTopic { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public string ResponseTopic { get; set; }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,5 +1,4 @@
 | 
				
			|||||||
<Project Sdk="Microsoft.NET.Sdk">
 | 
					<Project Sdk="Microsoft.NET.Sdk.Razor">
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	<Target Name="PostBuild" AfterTargets="PostBuildEvent">
 | 
						<Target Name="PostBuild" AfterTargets="PostBuildEvent">
 | 
				
			||||||
@@ -9,7 +8,30 @@
 | 
				
			|||||||
	</Target>
 | 
						</Target>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<ItemGroup>
 | 
				
			||||||
 | 
							<ProjectReference Include="..\..\Web\ThingsGateway.Components\ThingsGateway.Components.csproj">
 | 
				
			||||||
 | 
								<Private>false</Private>
 | 
				
			||||||
 | 
								<CopyLocalSatelliteAssemblies>false</CopyLocalSatelliteAssemblies>
 | 
				
			||||||
 | 
								<ExcludeAssets>runtime</ExcludeAssets>
 | 
				
			||||||
 | 
							</ProjectReference>
 | 
				
			||||||
 | 
						</ItemGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<ItemGroup>
 | 
				
			||||||
 | 
							<Compile Include="..\..\Demo\ThingsGateway.Foundation.Demo.Rcl\Components\DebugPage\DriverDebugUIBase.cs" Link="DebugPage\DriverDebugUIBase.cs" />
 | 
				
			||||||
 | 
							<Compile Include="..\..\Demo\ThingsGateway.Foundation.Demo.Rcl\Components\DebugPage\DriverDebugUIPage.razor.cs" Link="DebugPage\DriverDebugUIPage.razor.cs" />
 | 
				
			||||||
 | 
							<Compile Include="..\..\Demo\ThingsGateway.Foundation.Demo.Rcl\Components\DebugPage\SerialSessionPage.razor.cs" Link="DebugPage\SerialSessionPage.razor.cs" />
 | 
				
			||||||
 | 
							<Compile Include="..\..\Demo\ThingsGateway.Foundation.Demo.Rcl\Components\DebugPage\TcpClientPage.razor.cs" Link="DebugPage\TcpClientPage.razor.cs" />
 | 
				
			||||||
 | 
							<Compile Include="..\..\Demo\ThingsGateway.Foundation.Demo.Rcl\Components\DebugPage\TcpServerPage.razor.cs" Link="DebugPage\TcpServerPage.razor.cs" />
 | 
				
			||||||
 | 
							<Compile Include="..\..\Demo\ThingsGateway.Foundation.Demo.Rcl\Components\DebugPage\UdpSessionPage.razor.cs" Link="DebugPage\UdpSessionPage.razor.cs" />
 | 
				
			||||||
 | 
							<Content Include="..\..\Demo\ThingsGateway.Foundation.Demo.Rcl\Components\DebugPage\DriverDebugUIPage.razor" Link="DebugPage\DriverDebugUIPage.razor" />
 | 
				
			||||||
 | 
							<Content Include="..\..\Demo\ThingsGateway.Foundation.Demo.Rcl\Components\DebugPage\SerialSessionPage.razor" Link="DebugPage\SerialSessionPage.razor" />
 | 
				
			||||||
 | 
							<Content Include="..\..\Demo\ThingsGateway.Foundation.Demo.Rcl\Components\DebugPage\TcpClientPage.razor" Link="DebugPage\TcpClientPage.razor" />
 | 
				
			||||||
 | 
							<Content Include="..\..\Demo\ThingsGateway.Foundation.Demo.Rcl\Components\DebugPage\TcpServerPage.razor" Link="DebugPage\TcpServerPage.razor" />
 | 
				
			||||||
 | 
							<Content Include="..\..\Demo\ThingsGateway.Foundation.Demo.Rcl\Components\DebugPage\UdpSessionPage.razor" Link="DebugPage\UdpSessionPage.razor" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						</ItemGroup>
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
					
 | 
				
			||||||
</Project>
 | 
					</Project>
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										35
									
								
								framework/Plugin/ThingsGateway.Plugin.Mqtt/_Imports.razor
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								framework/Plugin/ThingsGateway.Plugin.Mqtt/_Imports.razor
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,35 @@
 | 
				
			|||||||
 | 
					@*
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					//  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
 | 
				
			||||||
 | 
					//  此代码版权(除特别声明外的代码)归作者本人Diego所有
 | 
				
			||||||
 | 
					//  源代码使用协议遵循本仓库的开源协议及附加协议
 | 
				
			||||||
 | 
					//  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  使用文档:https://diego2098.gitee.io/thingsgateway-docs/
 | 
				
			||||||
 | 
					//  QQ群:605534569
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					*@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@using System.Net.Http
 | 
				
			||||||
 | 
					@using Microsoft.AspNetCore.Components.Forms
 | 
				
			||||||
 | 
					@using Microsoft.AspNetCore.Components.Routing
 | 
				
			||||||
 | 
					@using Microsoft.AspNetCore.Components.Web
 | 
				
			||||||
 | 
					@using Microsoft.AspNetCore.Components.Web.Virtualization
 | 
				
			||||||
 | 
					@using Microsoft.JSInterop
 | 
				
			||||||
 | 
					@using BlazorComponent
 | 
				
			||||||
 | 
					@using Masa.Blazor
 | 
				
			||||||
 | 
					@using Masa.Blazor.Presets
 | 
				
			||||||
 | 
					@using System.Net.Http.Json
 | 
				
			||||||
 | 
					@using System.IO;
 | 
				
			||||||
 | 
					@using System.Text.Json;
 | 
				
			||||||
 | 
					@using System.Reflection;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@using ThingsGateway.Components;
 | 
				
			||||||
 | 
					@using ThingsGateway.Admin.Core;
 | 
				
			||||||
 | 
					@using ThingsGateway.Foundation;
 | 
				
			||||||
 | 
					@using ThingsGateway.Foundation.Extension.String;
 | 
				
			||||||
 | 
					@using ThingsGateway.Admin.Application;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@using ThingsGateway.Core;
 | 
				
			||||||
 | 
					@using ThingsGateway.Gateway.Application;
 | 
				
			||||||
 | 
					@using ThingsGateway.Gateway.Core;
 | 
				
			||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
<Project>
 | 
					<Project>
 | 
				
			||||||
	<PropertyGroup>
 | 
						<PropertyGroup>
 | 
				
			||||||
		<Version>3.0.0.2</Version>
 | 
							<Version>3.0.0.4</Version>
 | 
				
			||||||
		<LangVersion>latest</LangVersion>
 | 
							<LangVersion>latest</LangVersion>
 | 
				
			||||||
		<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
 | 
							<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
 | 
				
			||||||
		<Authors>Diego</Authors>
 | 
							<Authors>Diego</Authors>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
<Project>
 | 
					<Project>
 | 
				
			||||||
	<PropertyGroup>
 | 
						<PropertyGroup>
 | 
				
			||||||
		<Version>3.0.0.2</Version>
 | 
							<Version>3.0.0.4</Version>
 | 
				
			||||||
		<LangVersion>latest</LangVersion>
 | 
							<LangVersion>latest</LangVersion>
 | 
				
			||||||
		<ImplicitUsings>enable</ImplicitUsings>
 | 
							<ImplicitUsings>enable</ImplicitUsings>
 | 
				
			||||||
		<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
 | 
							<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -28,7 +28,7 @@ namespace ThingsGateway.Admin.Application;
 | 
				
			|||||||
/// </summary>
 | 
					/// </summary>
 | 
				
			||||||
public class OperDispatchProxy : AspectDispatchProxy, IDispatchProxy
 | 
					public class OperDispatchProxy : AspectDispatchProxy, IDispatchProxy
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    static readonly Parser Parser = Parser.GetDefault();
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 服务提供器,可以用来解析服务,如:Services.GetService()
 | 
					    /// 服务提供器,可以用来解析服务,如:Services.GetService()
 | 
				
			||||||
@@ -180,7 +180,8 @@ public class OperDispatchProxy : AspectDispatchProxy, IDispatchProxy
 | 
				
			|||||||
        ClientInfo clientInfo = null;
 | 
					        ClientInfo clientInfo = null;
 | 
				
			||||||
        if (str.HasValue)
 | 
					        if (str.HasValue)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            clientInfo = Parser.Parse(str);
 | 
					            var uaParser = Parser.GetDefault();
 | 
				
			||||||
 | 
					            clientInfo = uaParser.Parse(str);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        StringBuilder stringBuilder = new();
 | 
					        StringBuilder stringBuilder = new();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,6 +10,7 @@
 | 
				
			|||||||
//------------------------------------------------------------------------------
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
#endregion
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using Furion;
 | 
				
			||||||
using Furion.Schedule;
 | 
					using Furion.Schedule;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ThingsGateway.Admin.Application;
 | 
					namespace ThingsGateway.Admin.Application;
 | 
				
			||||||
@@ -25,7 +26,7 @@ public class LogJob : IJob
 | 
				
			|||||||
    public async Task ExecuteAsync(JobExecutingContext context, CancellationToken stoppingToken)
 | 
					    public async Task ExecuteAsync(JobExecutingContext context, CancellationToken stoppingToken)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        var db = DbContext.Db.CopyNew();
 | 
					        var db = DbContext.Db.CopyNew();
 | 
				
			||||||
        var daysAgo = 30; // 删除30天以前
 | 
					        var daysAgo = App.GetConfig<int?>("Logging:LogJob:DaysAgo") ?? 30;
 | 
				
			||||||
        await db.DeleteableWithAttr<SysVisitLog>().Where(u => u.CreateTime < DateTimeExtensions.CurrentDateTime.AddDays(-daysAgo)).ExecuteCommandAsync(stoppingToken); // 删除访问日志
 | 
					        await db.DeleteableWithAttr<SysVisitLog>().Where(u => u.CreateTime < DateTimeExtensions.CurrentDateTime.AddDays(-daysAgo)).ExecuteCommandAsync(stoppingToken); // 删除访问日志
 | 
				
			||||||
        await db.DeleteableWithAttr<SysOperateLog>().Where(u => u.CreateTime < DateTimeExtensions.CurrentDateTime.AddDays(-daysAgo)).ExecuteCommandAsync(stoppingToken); // 删除操作日志
 | 
					        await db.DeleteableWithAttr<SysOperateLog>().Where(u => u.CreateTime < DateTimeExtensions.CurrentDateTime.AddDays(-daysAgo)).ExecuteCommandAsync(stoppingToken); // 删除操作日志
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,7 +14,7 @@
 | 
				
			|||||||
@namespace ThingsGateway.Admin.Blazor
 | 
					@namespace ThingsGateway.Admin.Blazor
 | 
				
			||||||
@using Microsoft.AspNetCore.SignalR.Client;
 | 
					@using Microsoft.AspNetCore.SignalR.Client;
 | 
				
			||||||
@using ThingsGateway.Admin.Application;
 | 
					@using ThingsGateway.Admin.Application;
 | 
				
			||||||
 | 
					@implements IAsyncDisposable;
 | 
				
			||||||
@code {
 | 
					@code {
 | 
				
			||||||
    HubConnection _hubConnection;
 | 
					    HubConnection _hubConnection;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -32,6 +32,7 @@
 | 
				
			|||||||
            await _hubConnection.DisposeAsync();
 | 
					            await _hubConnection.DisposeAsync();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <inheritdoc/>
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
    protected override async Task OnAfterRenderAsync(bool firstRender)
 | 
					    protected override async Task OnAfterRenderAsync(bool firstRender)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,6 +10,7 @@
 | 
				
			|||||||
//------------------------------------------------------------------------------
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
#endregion
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using Furion;
 | 
				
			||||||
using Furion.Schedule;
 | 
					using Furion.Schedule;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ThingsGateway.Gateway.Application;
 | 
					namespace ThingsGateway.Gateway.Application;
 | 
				
			||||||
@@ -25,7 +26,7 @@ public class BackendAndRpcLogCleanJob : IJob
 | 
				
			|||||||
    public async Task ExecuteAsync(JobExecutingContext context, CancellationToken stoppingToken)
 | 
					    public async Task ExecuteAsync(JobExecutingContext context, CancellationToken stoppingToken)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        var db = DbContext.Db.CopyNew();
 | 
					        var db = DbContext.Db.CopyNew();
 | 
				
			||||||
        var daysAgo = 30; // 删除30天以前
 | 
					        var daysAgo = App.GetConfig<int?>("Logging:LogJob:DaysAgo") ?? 30;
 | 
				
			||||||
        await db.DeleteableWithAttr<BackendLog>().Where(u => u.LogTime < DateTimeExtensions.CurrentDateTime.AddDays(-daysAgo)).ExecuteCommandAsync();
 | 
					        await db.DeleteableWithAttr<BackendLog>().Where(u => u.LogTime < DateTimeExtensions.CurrentDateTime.AddDays(-daysAgo)).ExecuteCommandAsync();
 | 
				
			||||||
        await db.DeleteableWithAttr<RpcLog>().Where(u => u.LogTime < DateTimeExtensions.CurrentDateTime.AddDays(-daysAgo)).ExecuteCommandAsync();
 | 
					        await db.DeleteableWithAttr<RpcLog>().Where(u => u.LogTime < DateTimeExtensions.CurrentDateTime.AddDays(-daysAgo)).ExecuteCommandAsync();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -142,6 +142,21 @@ public class CollectDeviceWorker : BackgroundService
 | 
				
			|||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        CollectDeviceThreads.Remove(devThread);
 | 
					                        CollectDeviceThreads.Remove(devThread);
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 | 
					                    else
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        //单个设备重启时,注意同一线程的其他设备也会停止,需要重新初始化
 | 
				
			||||||
 | 
					                        foreach (var item in devThread.CollectDeviceCores)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            item.Init(item.Device, true);
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        await devThread.StartThreadAsync();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        //如果是组态更改过了,需要重新获取变量/设备运行态的值
 | 
				
			||||||
 | 
					                        if (isUpdateDb)
 | 
				
			||||||
 | 
					                            await StartOtherHostService();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                else
 | 
					                else
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -111,17 +111,21 @@ public class HardwareInfoWorker : BackgroundService
 | 
				
			|||||||
        APPInfo.Environment = App.HostEnvironment.IsDevelopment() ? "Development" : "Production";
 | 
					        APPInfo.Environment = App.HostEnvironment.IsDevelopment() ? "Development" : "Production";
 | 
				
			||||||
        APPInfo.Stage = App.HostEnvironment.IsStaging() ? "Stage" : "非Stage"; // 是否Stage环境
 | 
					        APPInfo.Stage = App.HostEnvironment.IsStaging() ? "Stage" : "非Stage"; // 是否Stage环境
 | 
				
			||||||
        APPInfo.UpdateTime = DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat();
 | 
					        APPInfo.UpdateTime = DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat();
 | 
				
			||||||
 | 
					        var enable = App.GetConfig<bool?>("HardwareInfo:Enable") ?? true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        while (!stoppingToken.IsCancellationRequested)
 | 
					        while (!stoppingToken.IsCancellationRequested)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            try
 | 
					            try
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                APPInfo.UpdateTime = DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat();
 | 
					                APPInfo.UpdateTime = DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat();
 | 
				
			||||||
                APPInfo.RemoteIp = await GetIpFromOnlineAsync();
 | 
					                APPInfo.RemoteIp = await GetIpFromOnlineAsync();
 | 
				
			||||||
 | 
					                if (enable)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
                    HardwareInfo?.RefreshMemoryStatus();
 | 
					                    HardwareInfo?.RefreshMemoryStatus();
 | 
				
			||||||
                    HardwareInfo?.RefreshMemoryList();
 | 
					                    HardwareInfo?.RefreshMemoryList();
 | 
				
			||||||
                    HardwareInfo?.RefreshNetworkAdapterList();
 | 
					                    HardwareInfo?.RefreshNetworkAdapterList();
 | 
				
			||||||
                    HardwareInfo?.RefreshCPUList();
 | 
					                    HardwareInfo?.RefreshCPUList();
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
                //10秒更新一次
 | 
					                //10秒更新一次
 | 
				
			||||||
                await Task.Delay(10000, stoppingToken);
 | 
					                await Task.Delay(10000, stoppingToken);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -159,6 +159,8 @@ public class UploadDeviceWorker : BackgroundService
 | 
				
			|||||||
                        {
 | 
					                        {
 | 
				
			||||||
                            item.Init(item.Device);
 | 
					                            item.Init(item.Device);
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
 | 
					                        await devThread.StartThreadAsync();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                else
 | 
					                else
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -27,7 +27,6 @@ namespace ThingsGateway.Web.Core
 | 
				
			|||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    public class LoggingMonitorComponent : IServiceComponent
 | 
					    public class LoggingMonitorComponent : IServiceComponent
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        private Parser Parser = Parser.GetDefault();
 | 
					 | 
				
			||||||
        /// <inheritdoc/>
 | 
					        /// <inheritdoc/>
 | 
				
			||||||
        public void Load(IServiceCollection services, ComponentContext componentContext)
 | 
					        public void Load(IServiceCollection services, ComponentContext componentContext)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -42,8 +41,9 @@ namespace ThingsGateway.Web.Core
 | 
				
			|||||||
                      //获取头
 | 
					                      //获取头
 | 
				
			||||||
                      var userAgent = httpContext.Request.Headers["User-Agent"];
 | 
					                      var userAgent = httpContext.Request.Headers["User-Agent"];
 | 
				
			||||||
                      if (string.IsNullOrEmpty(userAgent)) userAgent = "Other";//如果没有这个头就指定一个
 | 
					                      if (string.IsNullOrEmpty(userAgent)) userAgent = "Other";//如果没有这个头就指定一个
 | 
				
			||||||
 | 
					                      var uaParser = Parser.GetDefault();
 | 
				
			||||||
                      //获取客户端信息
 | 
					                      //获取客户端信息
 | 
				
			||||||
                      var client = Parser.Parse(userAgent);
 | 
					                      var client = uaParser.Parse(userAgent);
 | 
				
			||||||
                      // 获取控制器/操作描述器
 | 
					                      // 获取控制器/操作描述器
 | 
				
			||||||
                      var controllerActionDescriptor = context.ActionDescriptor as ControllerActionDescriptor;
 | 
					                      var controllerActionDescriptor = context.ActionDescriptor as ControllerActionDescriptor;
 | 
				
			||||||
                      //操作名称默认是控制器名加方法名,自定义操作名称要在action上加Description特性
 | 
					                      //操作名称默认是控制器名加方法名,自定义操作名称要在action上加Description特性
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,10 +1,12 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "$schema": "https://gitee.com/dotnetchina/Furion/raw/v4/schemas/v4/furion-schema.json",
 | 
					  "$schema": "https://gitee.com/dotnetchina/Furion/raw/v4/schemas/v4/furion-schema.json",
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  "Urls": "http://*:7200;",
 | 
					  "Urls": "http://*:7200;",
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  "Logging": {
 | 
					  "Logging": {
 | 
				
			||||||
    "LogLevel": {
 | 
					    "LogLevel": {
 | 
				
			||||||
      "File": "Information", //程序日志写入文件等级,不包含网关日志
 | 
					      "File": "Information", //程序日志写入文件等级,不包含网关日志
 | 
				
			||||||
      "BackendLog": "Information", //网关运行日志存入数据库等级,部署推荐Error
 | 
					      "BackendLog": "Information", //网关运行日志存入数据库等级,部署推荐Warning
 | 
				
			||||||
      "Default": "Information", //默认等级
 | 
					      "Default": "Information", //默认等级
 | 
				
			||||||
      "Console": "Information", //控制台输出日志等级
 | 
					      "Console": "Information", //控制台输出日志等级
 | 
				
			||||||
      "Microsoft": "Warning",
 | 
					      "Microsoft": "Warning",
 | 
				
			||||||
@@ -12,8 +14,16 @@
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
    "LogEnable": {
 | 
					    "LogEnable": {
 | 
				
			||||||
      "File": true //程序日志写入文件
 | 
					      "File": true //程序日志写入文件
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "LogJob": {
 | 
				
			||||||
 | 
					      "DaysAgo": 30 //删除多少天前的日志,任务会间隔24小时执行一次
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  "HardwareInfo": {
 | 
				
			||||||
 | 
					    "Enable": true //启用硬件信息获取,部分系统/硬件不支持相关方法,设为false
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    //动态API设备
 | 
					    //动态API设备
 | 
				
			||||||
    "DynamicApiControllerSettings": {
 | 
					    "DynamicApiControllerSettings": {
 | 
				
			||||||
      "LowercaseRoute": false, //是否采用小写路由,bool 类型,默认 true
 | 
					      "LowercaseRoute": false, //是否采用小写路由,bool 类型,默认 true
 | 
				
			||||||
@@ -41,4 +51,4 @@
 | 
				
			|||||||
      "WithExposedHeaders": [ "Content-Disposition" ], // 如果前端不代理且是axios请求
 | 
					      "WithExposedHeaders": [ "Content-Disposition" ], // 如果前端不代理且是axios请求
 | 
				
			||||||
      "SignalRSupport": true // 启用 SignalR 跨域支持
 | 
					      "SignalRSupport": true // 启用 SignalR 跨域支持
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					  }
 | 
				
			||||||
@@ -3,7 +3,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	<PropertyGroup>
 | 
						<PropertyGroup>
 | 
				
			||||||
		<ApplicationIcon>wwwroot\favicon.ico</ApplicationIcon>
 | 
							<ApplicationIcon>wwwroot\favicon.ico</ApplicationIcon>
 | 
				
			||||||
		<ServerGarbageCollection>false</ServerGarbageCollection>
 | 
							<!--<ServerGarbageCollection>false</ServerGarbageCollection>-->
 | 
				
			||||||
		<!--<PlatformTarget>x86</PlatformTarget>-->
 | 
							<!--<PlatformTarget>x86</PlatformTarget>-->
 | 
				
			||||||
	</PropertyGroup>
 | 
						</PropertyGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user