Compare commits
4 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
24bc60abf0 | ||
![]() |
31eee6b009 | ||
![]() |
c5da565a8f | ||
![]() |
947cd712e1 |
@@ -1,6 +1,6 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<Version>3.0.0.2</Version>
|
||||
<Version>3.0.0.4</Version>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
|
||||
<Authors>Diego</Authors>
|
||||
|
@@ -124,6 +124,15 @@ public partial class MainLayout
|
||||
"Title": "OPCUAClient"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Title": "Mqtt",
|
||||
"Children": [
|
||||
{
|
||||
"Href": "/MqttClient",
|
||||
"Title": "MqttClient"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
|
@@ -45,6 +45,13 @@
|
||||
|
||||
<ItemGroup>
|
||||
<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" />
|
||||
<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" />
|
||||
@@ -117,5 +124,17 @@
|
||||
</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>
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<Version>3.0.0.2</Version>
|
||||
<Version>3.0.0.4</Version>
|
||||
<GenerateDocumentationFile>True</GenerateDocumentationFile>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<TargetFrameworks>net45;netstandard2.0;net6.0;net7.0</TargetFrameworks>
|
||||
|
@@ -440,9 +440,7 @@ public class TcpClientBase : BaseSocket, ITcpClient
|
||||
{
|
||||
throw new TimeoutException("连接超时");
|
||||
}
|
||||
{
|
||||
success(socket);
|
||||
}
|
||||
success(socket);
|
||||
|
||||
#else
|
||||
using CancellationTokenSource cancellationTokenSource = new();
|
||||
@@ -465,11 +463,10 @@ public class TcpClientBase : BaseSocket, ITcpClient
|
||||
else
|
||||
{
|
||||
socket?.SafeDispose();
|
||||
socket.Close();
|
||||
throw new TimeoutException("连接超时");
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<Version>3.0.0.2</Version>
|
||||
<Version>3.0.0.4</Version>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
|
||||
@@ -11,7 +11,6 @@
|
||||
<SignAssembly>True</SignAssembly>
|
||||
<DelaySign>False</DelaySign>
|
||||
<SatelliteResourceLanguages>zh-Hans</SatelliteResourceLanguages>
|
||||
<GenerateDocumentationFile>True</GenerateDocumentationFile>
|
||||
|
||||
</PropertyGroup>
|
||||
|
||||
|
@@ -10,6 +10,9 @@
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
global using ThingsGateway.Components;
|
||||
global using ThingsGateway.Foundation;
|
||||
global using ThingsGateway.Foundation.Serial;
|
||||
global using ThingsGateway.Foundation.Sockets;
|
||||
global using ThingsGateway.Gateway.Application;
|
||||
global using ThingsGateway.Gateway.Core;
|
||||
|
@@ -22,6 +22,7 @@ using MQTTnet.Client;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Text;
|
||||
|
||||
using ThingsGateway.Foundation.Demo;
|
||||
using ThingsGateway.Foundation.Extension.ConcurrentQueue;
|
||||
using ThingsGateway.Foundation.Extension.Generic;
|
||||
using ThingsGateway.Foundation.Extension.String;
|
||||
@@ -55,7 +56,7 @@ public class MqttClient : UpLoadBase
|
||||
|
||||
private TimerTick exVariableTimerTick;
|
||||
/// <inheritdoc/>
|
||||
public override Type DriverDebugUIType => null;
|
||||
public override Type DriverDebugUIType => typeof(MqttClientDebugPage);
|
||||
/// <inheritdoc/>
|
||||
public override UpDriverPropertyBase DriverPropertys => driverPropertys;
|
||||
|
||||
|
@@ -10,6 +10,10 @@
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
using ThingsGateway.Foundation;
|
||||
|
||||
namespace ThingsGateway.Plugin.Mqtt;
|
||||
|
||||
/// <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 ThingsGateway.Foundation;
|
||||
|
||||
namespace ThingsGateway.Plugin.Mqtt
|
||||
{
|
||||
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,6 +1,5 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk.Razor">
|
||||
|
||||
|
||||
|
||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
||||
|
||||
@@ -9,7 +8,30 @@
|
||||
</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>
|
||||
|
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>
|
||||
<PropertyGroup>
|
||||
<Version>3.0.0.2</Version>
|
||||
<Version>3.0.0.4</Version>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
|
||||
<Authors>Diego</Authors>
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<Version>3.0.0.2</Version>
|
||||
<Version>3.0.0.4</Version>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
|
||||
|
@@ -28,7 +28,7 @@ namespace ThingsGateway.Admin.Application;
|
||||
/// </summary>
|
||||
public class OperDispatchProxy : AspectDispatchProxy, IDispatchProxy
|
||||
{
|
||||
static readonly Parser Parser = Parser.GetDefault();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 服务提供器,可以用来解析服务,如:Services.GetService()
|
||||
@@ -180,7 +180,8 @@ public class OperDispatchProxy : AspectDispatchProxy, IDispatchProxy
|
||||
ClientInfo clientInfo = null;
|
||||
if (str.HasValue)
|
||||
{
|
||||
clientInfo = Parser.Parse(str);
|
||||
var uaParser = Parser.GetDefault();
|
||||
clientInfo = uaParser.Parse(str);
|
||||
}
|
||||
|
||||
StringBuilder stringBuilder = new();
|
||||
|
@@ -10,6 +10,7 @@
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using Furion;
|
||||
using Furion.Schedule;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
@@ -25,7 +26,7 @@ public class LogJob : IJob
|
||||
public async Task ExecuteAsync(JobExecutingContext context, CancellationToken stoppingToken)
|
||||
{
|
||||
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<SysOperateLog>().Where(u => u.CreateTime < DateTimeExtensions.CurrentDateTime.AddDays(-daysAgo)).ExecuteCommandAsync(stoppingToken); // 删除操作日志
|
||||
}
|
||||
|
@@ -14,7 +14,7 @@
|
||||
@namespace ThingsGateway.Admin.Blazor
|
||||
@using Microsoft.AspNetCore.SignalR.Client;
|
||||
@using ThingsGateway.Admin.Application;
|
||||
|
||||
@implements IAsyncDisposable;
|
||||
@code {
|
||||
HubConnection _hubConnection;
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
await _hubConnection.DisposeAsync();
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
|
@@ -10,6 +10,7 @@
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using Furion;
|
||||
using Furion.Schedule;
|
||||
|
||||
namespace ThingsGateway.Gateway.Application;
|
||||
@@ -25,7 +26,7 @@ public class BackendAndRpcLogCleanJob : IJob
|
||||
public async Task ExecuteAsync(JobExecutingContext context, CancellationToken stoppingToken)
|
||||
{
|
||||
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<RpcLog>().Where(u => u.LogTime < DateTimeExtensions.CurrentDateTime.AddDays(-daysAgo)).ExecuteCommandAsync();
|
||||
}
|
||||
|
@@ -142,6 +142,21 @@ public class CollectDeviceWorker : BackgroundService
|
||||
{
|
||||
CollectDeviceThreads.Remove(devThread);
|
||||
}
|
||||
else
|
||||
{
|
||||
//单个设备重启时,注意同一线程的其他设备也会停止,需要重新初始化
|
||||
foreach (var item in devThread.CollectDeviceCores)
|
||||
{
|
||||
item.Init(item.Device, true);
|
||||
}
|
||||
|
||||
await devThread.StartThreadAsync();
|
||||
|
||||
//如果是组态更改过了,需要重新获取变量/设备运行态的值
|
||||
if (isUpdateDb)
|
||||
await StartOtherHostService();
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@@ -111,17 +111,21 @@ public class HardwareInfoWorker : BackgroundService
|
||||
APPInfo.Environment = App.HostEnvironment.IsDevelopment() ? "Development" : "Production";
|
||||
APPInfo.Stage = App.HostEnvironment.IsStaging() ? "Stage" : "非Stage"; // 是否Stage环境
|
||||
APPInfo.UpdateTime = DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat();
|
||||
var enable = App.GetConfig<bool?>("HardwareInfo:Enable") ?? true;
|
||||
|
||||
while (!stoppingToken.IsCancellationRequested)
|
||||
{
|
||||
try
|
||||
{
|
||||
APPInfo.UpdateTime = DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat();
|
||||
APPInfo.RemoteIp = await GetIpFromOnlineAsync();
|
||||
|
||||
HardwareInfo?.RefreshMemoryStatus();
|
||||
HardwareInfo?.RefreshMemoryList();
|
||||
HardwareInfo?.RefreshNetworkAdapterList();
|
||||
HardwareInfo?.RefreshCPUList();
|
||||
if (enable)
|
||||
{
|
||||
HardwareInfo?.RefreshMemoryStatus();
|
||||
HardwareInfo?.RefreshMemoryList();
|
||||
HardwareInfo?.RefreshNetworkAdapterList();
|
||||
HardwareInfo?.RefreshCPUList();
|
||||
}
|
||||
//10秒更新一次
|
||||
await Task.Delay(10000, stoppingToken);
|
||||
}
|
||||
|
@@ -159,6 +159,8 @@ public class UploadDeviceWorker : BackgroundService
|
||||
{
|
||||
item.Init(item.Device);
|
||||
}
|
||||
await devThread.StartThreadAsync();
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@@ -27,7 +27,6 @@ namespace ThingsGateway.Web.Core
|
||||
/// </summary>
|
||||
public class LoggingMonitorComponent : IServiceComponent
|
||||
{
|
||||
private Parser Parser = Parser.GetDefault();
|
||||
/// <inheritdoc/>
|
||||
public void Load(IServiceCollection services, ComponentContext componentContext)
|
||||
{
|
||||
@@ -42,8 +41,9 @@ namespace ThingsGateway.Web.Core
|
||||
//获取头
|
||||
var userAgent = httpContext.Request.Headers["User-Agent"];
|
||||
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;
|
||||
//操作名称默认是控制器名加方法名,自定义操作名称要在action上加Description特性
|
||||
|
@@ -1,10 +1,12 @@
|
||||
{
|
||||
"$schema": "https://gitee.com/dotnetchina/Furion/raw/v4/schemas/v4/furion-schema.json",
|
||||
|
||||
"Urls": "http://*:7200;",
|
||||
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"File": "Information", //程序日志写入文件等级,不包含网关日志
|
||||
"BackendLog": "Information", //网关运行日志存入数据库等级,部署推荐Error
|
||||
"BackendLog": "Information", //网关运行日志存入数据库等级,部署推荐Warning
|
||||
"Default": "Information", //默认等级
|
||||
"Console": "Information", //控制台输出日志等级
|
||||
"Microsoft": "Warning",
|
||||
@@ -12,33 +14,41 @@
|
||||
},
|
||||
"LogEnable": {
|
||||
"File": true //程序日志写入文件
|
||||
},
|
||||
"LogJob": {
|
||||
"DaysAgo": 30 //删除多少天前的日志,任务会间隔24小时执行一次
|
||||
}
|
||||
},
|
||||
//动态API设备
|
||||
"DynamicApiControllerSettings": {
|
||||
"LowercaseRoute": false, //是否采用小写路由,bool 类型,默认 true
|
||||
"KeepName": true, //是否保持原有名称不处理,bool,默认 false
|
||||
"AsLowerCamelCase": true //启用小驼峰命名(首字母小写),默认 false
|
||||
|
||||
"HardwareInfo": {
|
||||
"Enable": true //启用硬件信息获取,部分系统/硬件不支持相关方法,设为false
|
||||
},
|
||||
|
||||
"FriendlyExceptionSettings": {
|
||||
"DefaultErrorMessage": "系统异常,请联系管理员",
|
||||
"HideErrorCode": true
|
||||
},
|
||||
//动态API设备
|
||||
"DynamicApiControllerSettings": {
|
||||
"LowercaseRoute": false, //是否采用小写路由,bool 类型,默认 true
|
||||
"KeepName": true, //是否保持原有名称不处理,bool,默认 false
|
||||
"AsLowerCamelCase": true //启用小驼峰命名(首字母小写),默认 false
|
||||
},
|
||||
|
||||
//排除特定配置文件
|
||||
"IgnoreConfigurationFiles": [
|
||||
"Navs.json",
|
||||
"sys_user.json",
|
||||
"sys_config.json",
|
||||
"sys_relation.json",
|
||||
"sys_resource.json",
|
||||
"sys_role.json",
|
||||
"driver_plugin.json"
|
||||
],
|
||||
"FriendlyExceptionSettings": {
|
||||
"DefaultErrorMessage": "系统异常,请联系管理员",
|
||||
"HideErrorCode": true
|
||||
},
|
||||
|
||||
"CorsAccessorSettings": {
|
||||
"WithExposedHeaders": [ "Content-Disposition" ], // 如果前端不代理且是axios请求
|
||||
"SignalRSupport": true // 启用 SignalR 跨域支持
|
||||
}
|
||||
}
|
||||
//排除特定配置文件
|
||||
"IgnoreConfigurationFiles": [
|
||||
"Navs.json",
|
||||
"sys_user.json",
|
||||
"sys_config.json",
|
||||
"sys_relation.json",
|
||||
"sys_resource.json",
|
||||
"sys_role.json",
|
||||
"driver_plugin.json"
|
||||
],
|
||||
|
||||
"CorsAccessorSettings": {
|
||||
"WithExposedHeaders": [ "Content-Disposition" ], // 如果前端不代理且是axios请求
|
||||
"SignalRSupport": true // 启用 SignalR 跨域支持
|
||||
}
|
||||
}
|
@@ -3,7 +3,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<ApplicationIcon>wwwroot\favicon.ico</ApplicationIcon>
|
||||
<ServerGarbageCollection>false</ServerGarbageCollection>
|
||||
<!--<ServerGarbageCollection>false</ServerGarbageCollection>-->
|
||||
<!--<PlatformTarget>x86</PlatformTarget>-->
|
||||
</PropertyGroup>
|
||||
|
||||
|
Reference in New Issue
Block a user