😎1、优化MQTT相关 2、升级依赖

This commit is contained in:
zuohuaijun 2025-02-23 03:10:34 +08:00
parent 7e1cdeaffa
commit 1358cd397d
23 changed files with 1085 additions and 278 deletions

View File

@ -3,12 +3,11 @@
// MQTT // MQTT
"Mqtt": { "Mqtt": {
"MqttServerId": "MqttServer", // ClientId "Enabled": false, //
"Enabled": true, // "Port": "1883", //
"Logging": true, // "IPAddress": "", // IP
"ConsoleOutput": true, // "ConnectionBacklog": 1000, //
"ConnectionBacklog": 1000, "MqttServerId": "Admin.NET.MQTT", // ClientId
"Port": "1883", "Logging": false //
"IPAddress": ""
} }
} }

View File

@ -14,20 +14,20 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="AlibabaCloud.SDK.Dysmsapi20170525" Version="3.1.1" /> <PackageReference Include="AlibabaCloud.SDK.Dysmsapi20170525" Version="3.1.1" />
<PackageReference Include="AlipaySDKNet.Standard" Version="4.9.409" /> <PackageReference Include="AlipaySDKNet.Standard" Version="4.9.412" />
<PackageReference Include="AngleSharp" Version="1.2.0" /> <PackageReference Include="AngleSharp" Version="1.2.0" />
<PackageReference Include="AspectCore.Extensions.Reflection" Version="2.4.0" /> <PackageReference Include="AspectCore.Extensions.Reflection" Version="2.4.0" />
<PackageReference Include="AspNetCoreRateLimit" Version="5.0.0" /> <PackageReference Include="AspNetCoreRateLimit" Version="5.0.0" />
<PackageReference Include="BouncyCastle.Cryptography" Version="2.5.1" Aliases="BouncyCastleV2" /> <PackageReference Include="BouncyCastle.Cryptography" Version="2.5.1" Aliases="BouncyCastleV2" />
<PackageReference Include="Elastic.Clients.Elasticsearch" Version="8.17.1" /> <PackageReference Include="Elastic.Clients.Elasticsearch" Version="8.17.1" />
<PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.9.7.9" /> <PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.9.7.10" />
<PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.9.7.9" /> <PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.9.7.10" />
<PackageReference Include="Furion.Pure" Version="4.9.7.9" /> <PackageReference Include="Furion.Pure" Version="4.9.7.10" />
<PackageReference Include="Hardware.Info" Version="101.0.1" /> <PackageReference Include="Hardware.Info" Version="101.0.1" />
<PackageReference Include="Hashids.net" Version="1.7.0" /> <PackageReference Include="Hashids.net" Version="1.7.0" />
<PackageReference Include="IPTools.China" Version="1.6.0" /> <PackageReference Include="IPTools.China" Version="1.6.0" />
<PackageReference Include="IPTools.International" Version="1.6.0" /> <PackageReference Include="IPTools.International" Version="1.6.0" />
<PackageReference Include="log4net" Version="3.0.3" /> <PackageReference Include="log4net" Version="3.0.4" />
<PackageReference Include="Magicodes.IE.Excel" Version="2.7.5.2" /> <PackageReference Include="Magicodes.IE.Excel" Version="2.7.5.2" />
<PackageReference Include="Magicodes.IE.Pdf" Version="2.7.5.2" /> <PackageReference Include="Magicodes.IE.Pdf" Version="2.7.5.2" />
<PackageReference Include="Magicodes.IE.Word" Version="2.7.5.2" /> <PackageReference Include="Magicodes.IE.Word" Version="2.7.5.2" />
@ -48,7 +48,7 @@
<PackageReference Include="SSH.NET" Version="2024.2.0" /> <PackageReference Include="SSH.NET" Version="2024.2.0" />
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.6.0.2" /> <PackageReference Include="System.Linq.Dynamic.Core" Version="1.6.0.2" />
<PackageReference Include="System.Net.Http" Version="4.3.4" /> <PackageReference Include="System.Net.Http" Version="4.3.4" />
<PackageReference Include="TencentCloudSDK.Sms" Version="3.0.1182" /> <PackageReference Include="TencentCloudSDK.Sms" Version="3.0.1184" />
<PackageReference Include="UAParser" Version="3.1.47" /> <PackageReference Include="UAParser" Version="3.1.47" />
<PackageReference Include="Yitter.IdGenerator" Version="1.0.14" /> <PackageReference Include="Yitter.IdGenerator" Version="1.0.14" />
</ItemGroup> </ItemGroup>

View File

@ -6,7 +6,6 @@
namespace Admin.NET.Core; namespace Admin.NET.Core;
using Furion.Logging.Extensions;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using MQTTnet; using MQTTnet;
using MQTTnet.Protocol; using MQTTnet.Protocol;
@ -19,45 +18,30 @@ using System.Threading.Tasks;
/// <summary> /// <summary>
/// MQTT 服务 /// MQTT 服务
/// </summary> /// </summary>
public class MqttHostedService(IOptions<MqttOptions> mqttOptions, ISqlSugarClient db) : IHostedService, ISingleton public class MqttHostedService(IOptions<MqttOptions> mqttOptions) : IHostedService, ISingleton
{ {
private const string ServerClientId = "Admin.NET.MQTT";
public static MqttServer MqttServer { get; set; }
private readonly MqttOptions _mqttOptions = mqttOptions.Value; private readonly MqttOptions _mqttOptions = mqttOptions.Value;
private readonly ISqlSugarClient _db = db; public static MqttServer MqttServer { get; set; }
private bool _isLogging = false; public static readonly List<MqttEventInterceptor> MqttEventInterceptors = []; // MQTT 事件拦截器集合
private bool _consoleOutput = false;
static List<MqttEventHandler> mqttEventHandlers = new List<MqttEventHandler>(); /// <summary>
/// 注册 MQTT 事件拦截器
public static void RegistMqttEventHandler(MqttEventHandler eh, int order) /// </summary>
/// <param name="mqttEventInterceptor"></param>
/// <param name="order"></param>
public static void AddMqttEventInterceptor(MqttEventInterceptor mqttEventInterceptor, int order = 0)
{ {
eh.Order = order; mqttEventInterceptor.Order = order;
mqttEventHandlers.Add(eh); MqttEventInterceptors.Add(mqttEventInterceptor);
mqttEventHandlers.Sort((a,b) => b.Order - a.Order); MqttEventInterceptors.Sort((a, b) => b.Order - a.Order);
}
public async void PublicMessage(string topic, string message)
{
// 创建一个 MQTT 应用消息
var applicationMessage = new MqttApplicationMessageBuilder()
.WithTopic(topic)
.WithPayload(message)
.Build();
// 记录日志
Log($"服务器发布主题: {topic}, 内容:{message}");
await MqttServer.InjectApplicationMessage(new InjectedMqttApplicationMessage(applicationMessage)
{
SenderClientId = _mqttOptions.MqttServerId
});
} }
public async Task StartAsync(CancellationToken cancellationToken) public async Task StartAsync(CancellationToken cancellationToken)
{ {
if (!_mqttOptions.Enabled) return; if (!_mqttOptions.Enabled) return;
_isLogging = _mqttOptions.Logging;
_consoleOutput = _mqttOptions.ConsoleOutput; // 注册 MQTT 自定义客户端验证事件拦截器
AddMqttEventInterceptor(new DefaultMqttEventInterceptor());
var options = new MqttServerOptionsBuilder() var options = new MqttServerOptionsBuilder()
.WithDefaultEndpoint() // 默认地址127.0.0.1 .WithDefaultEndpoint() // 默认地址127.0.0.1
@ -102,7 +86,7 @@ public class MqttHostedService(IOptions<MqttOptions> mqttOptions, ISqlSugarClien
private async Task MqttServer_StoppedAsync(EventArgs arg) private async Task MqttServer_StoppedAsync(EventArgs arg)
{ {
Console.WriteLine($"【MQTT】服务已关闭...... {DateTime.Now}"); Console.WriteLine($"【MQTT】服务已关闭...... {DateTime.Now}");
foreach (var eh in mqttEventHandlers) foreach (var eh in MqttEventInterceptors)
{ {
await eh.StoppedAsync(arg); await eh.StoppedAsync(arg);
} }
@ -115,7 +99,7 @@ public class MqttHostedService(IOptions<MqttOptions> mqttOptions, ISqlSugarClien
/// <returns></returns> /// <returns></returns>
private async Task MqttServer_ValidatingConnectionAsync(ValidatingConnectionEventArgs arg) private async Task MqttServer_ValidatingConnectionAsync(ValidatingConnectionEventArgs arg)
{ {
foreach (var eh in mqttEventHandlers) foreach (var eh in MqttEventInterceptors)
{ {
await eh.ValidatingConnectionAsync(arg); await eh.ValidatingConnectionAsync(arg);
if (arg.ReasonCode != MqttConnectReasonCode.Success) if (arg.ReasonCode != MqttConnectReasonCode.Success)
@ -130,11 +114,12 @@ public class MqttHostedService(IOptions<MqttOptions> mqttOptions, ISqlSugarClien
/// <returns></returns> /// <returns></returns>
private async Task MqttServer_ClientConnectedAsync(ClientConnectedEventArgs arg) private async Task MqttServer_ClientConnectedAsync(ClientConnectedEventArgs arg)
{ {
Log($"客户端连接客户端ID=【{arg.ClientId}】已连接:用户名=【{arg.UserName}】地址=【{arg.RemoteEndPoint}】 {DateTime.Now}"); foreach (var eh in MqttEventInterceptors)
foreach (var eh in mqttEventHandlers)
{ {
await eh.ClientConnectedAsync(arg); await eh.ClientConnectedAsync(arg);
} }
Logging($"客户端连接客户端ID=【{arg.ClientId}】已连接:用户名=【{arg.UserName}】地址=【{arg.RemoteEndPoint}】 {DateTime.Now}");
} }
/// <summary> /// <summary>
@ -145,11 +130,12 @@ public class MqttHostedService(IOptions<MqttOptions> mqttOptions, ISqlSugarClien
/// <exception cref="NotImplementedException"></exception> /// <exception cref="NotImplementedException"></exception>
private async Task MqttServer_ClientDisconnectedAsync(ClientDisconnectedEventArgs arg) private async Task MqttServer_ClientDisconnectedAsync(ClientDisconnectedEventArgs arg)
{ {
Log($"客户端断开客户端ID=【{arg.ClientId}】已断开:用户名=【{arg.UserName}】地址=【{arg.RemoteEndPoint}】 {DateTime.Now}"); foreach (var eh in MqttEventInterceptors)
foreach (var eh in mqttEventHandlers)
{ {
await eh.ClientDisconnectedAsync(arg); await eh.ClientDisconnectedAsync(arg);
} }
Logging($"客户端断开客户端ID=【{arg.ClientId}】已断开:用户名=【{arg.UserName}】地址=【{arg.RemoteEndPoint}】 {DateTime.Now}");
} }
/// <summary> /// <summary>
@ -159,11 +145,12 @@ public class MqttHostedService(IOptions<MqttOptions> mqttOptions, ISqlSugarClien
/// <returns></returns> /// <returns></returns>
private async Task MqttServer_ClientSubscribedTopicAsync(ClientSubscribedTopicEventArgs arg) private async Task MqttServer_ClientSubscribedTopicAsync(ClientSubscribedTopicEventArgs arg)
{ {
Log($"订阅主题客户端ID=【{arg.ClientId}】订阅主题=【{arg.TopicFilter}】 {DateTime.Now}"); foreach (var eh in MqttEventInterceptors)
foreach (var eh in mqttEventHandlers)
{ {
await eh.ClientSubscribedTopicAsync(arg); await eh.ClientSubscribedTopicAsync(arg);
} }
Logging($"订阅主题客户端ID=【{arg.ClientId}】订阅主题=【{arg.TopicFilter}】 {DateTime.Now}");
} }
/// <summary> /// <summary>
@ -173,15 +160,16 @@ public class MqttHostedService(IOptions<MqttOptions> mqttOptions, ISqlSugarClien
/// <returns></returns> /// <returns></returns>
private async Task MqttServer_ClientUnsubscribedTopicAsync(ClientUnsubscribedTopicEventArgs arg) private async Task MqttServer_ClientUnsubscribedTopicAsync(ClientUnsubscribedTopicEventArgs arg)
{ {
Log($"取消订阅客户端ID=【{arg.ClientId}】取消订阅主题=【{arg.TopicFilter}】 {DateTime.Now}"); foreach (var eh in MqttEventInterceptors)
foreach (var eh in mqttEventHandlers)
{ {
await eh.ClientUnsubscribedTopicAsync(arg); await eh.ClientUnsubscribedTopicAsync(arg);
} }
Logging($"取消订阅客户端ID=【{arg.ClientId}】取消订阅主题=【{arg.TopicFilter}】 {DateTime.Now}");
} }
/// <summary> /// <summary>
/// 拦截接收消息 /// 拦截发布的消息事件
/// </summary> /// </summary>
/// <param name="arg"></param> /// <param name="arg"></param>
/// <returns></returns> /// <returns></returns>
@ -190,25 +178,48 @@ public class MqttHostedService(IOptions<MqttOptions> mqttOptions, ISqlSugarClien
if (string.Equals(arg.ClientId, _mqttOptions.MqttServerId)) if (string.Equals(arg.ClientId, _mqttOptions.MqttServerId))
return; return;
Log($"拦截消息客户端ID=【{arg.ClientId}】 Topic主题=【{arg.ApplicationMessage.Topic}】 消息=【{Encoding.UTF8.GetString(arg.ApplicationMessage.Payload)}】 qos等级=【{arg.ApplicationMessage.QualityOfServiceLevel}】 {DateTime.Now}"); foreach (var eh in MqttEventInterceptors)
foreach (var eh in mqttEventHandlers)
{ {
await eh.InterceptingPublishAsync(arg); await eh.InterceptingPublishAsync(arg);
} }
Logging($"拦截消息客户端ID=【{arg.ClientId}】 Topic主题=【{arg.ApplicationMessage.Topic}】 消息=【{Encoding.UTF8.GetString(arg.ApplicationMessage.Payload)}】 qos等级=【{arg.ApplicationMessage.QualityOfServiceLevel}】 {DateTime.Now}");
} }
/// <summary> /// <summary>
/// 消息未被消费 /// 未被消费的消息事件
/// </summary> /// </summary>
/// <param name="arg"></param> /// <param name="arg"></param>
/// <returns></returns> /// <returns></returns>
private async Task MqttServer_ApplicationMessageNotConsumedAsync(ApplicationMessageNotConsumedEventArgs arg) private async Task MqttServer_ApplicationMessageNotConsumedAsync(ApplicationMessageNotConsumedEventArgs arg)
{ {
Console.WriteLine($"接收消息发送端ID=【{arg.SenderId}】 Topic主题=【{arg.ApplicationMessage.Topic}】 消息=【{Encoding.UTF8.GetString(arg.ApplicationMessage.Payload)}】 qos等级=【{arg.ApplicationMessage.QualityOfServiceLevel}】 {DateTime.Now}"); foreach (var eh in MqttEventInterceptors)
foreach (var eh in mqttEventHandlers)
{ {
await eh.ApplicationMessageNotConsumedAsync(arg); await eh.ApplicationMessageNotConsumedAsync(arg);
} }
Logging($"接收消息发送端ID=【{arg.SenderId}】 Topic主题=【{arg.ApplicationMessage.Topic}】 消息=【{Encoding.UTF8.GetString(arg.ApplicationMessage.Payload)}】 qos等级=【{arg.ApplicationMessage.QualityOfServiceLevel}】 {DateTime.Now}");
}
/// <summary>
/// 发布主题消息
/// </summary>
/// <param name="topic"></param>
/// <param name="message"></param>
public async Task PublicMessageAsync(string topic, string message)
{
var applicationMessage = new MqttApplicationMessageBuilder()
.WithTopic(topic)
.WithPayload(message)
.Build();
await MqttServer.InjectApplicationMessage(new InjectedMqttApplicationMessage(applicationMessage)
{
SenderClientId = _mqttOptions.MqttServerId,
SenderUserName = _mqttOptions.MqttServerId,
});
Logging($"服务器发布主题:{topic}, 内容:{message}");
} }
public Task StopAsync(CancellationToken cancellationToken) public Task StopAsync(CancellationToken cancellationToken)
@ -216,11 +227,13 @@ public class MqttHostedService(IOptions<MqttOptions> mqttOptions, ISqlSugarClien
return Task.CompletedTask; return Task.CompletedTask;
} }
protected void Log(string msg) /// <summary>
/// 输出日志
/// </summary>
/// <param name="msg"></param>
protected void Logging(string msg)
{ {
if (_consoleOutput) if (!_mqttOptions.Logging) return;
Console.WriteLine(msg); LoggingWriter.LogInformation(msg);
if (_isLogging)
msg.LogDebug();
} }
} }

View File

@ -6,38 +6,42 @@
using MQTTnet.Protocol; using MQTTnet.Protocol;
using MQTTnet.Server; using MQTTnet.Server;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Admin.NET.Core; namespace Admin.NET.Core;
public class MqttEventHandlerForAdminNet : MqttEventHandler
/// <summary>
/// 默认 MQTT 事件拦截器
/// </summary>
public class DefaultMqttEventInterceptor : MqttEventInterceptor
{ {
public override async Task ValidatingConnectionAsync(ValidatingConnectionEventArgs arg) public new int Order = int.MinValue;
public override Task ValidatingConnectionAsync(ValidatingConnectionEventArgs arg)
{ {
ISqlSugarClient _db = App.GetRequiredService<ISqlSugarClient>(); var _db = App.GetRequiredService<ISqlSugarClient>();
// 验证账号 // 验证账号
var user = _db.Queryable<SysUser>().First(u => u.Account == arg.UserName); var user = _db.Queryable<SysUser>().First(u => u.Account == arg.UserName);
if (user == null) if (user == null)
{ {
arg.ReasonCode = MqttConnectReasonCode.BadUserNameOrPassword; arg.ReasonCode = MqttConnectReasonCode.BadUserNameOrPassword;
Log($"客户端验证客户端ID=【{arg.ClientId}】用户名不存在 {DateTime.Now} "); Logging($"客户端验证客户端ID=【{arg.ClientId}】用户名不存在 {DateTime.Now} ");
return; return Task.CompletedTask;
} }
// 验证密码 // 验证密码
var password = arg.Password; var password = arg.Password;
if (CryptogramUtil.CryptoType == CryptogramEnum.MD5.ToString()) if (CryptogramUtil.CryptoType == CryptogramEnum.MD5.ToString())
{ {
if (user.Password.Equals(MD5Encryption.Encrypt(password))) return; if (user.Password.Equals(MD5Encryption.Encrypt(password)))
return Task.CompletedTask;
} }
else else
{ {
if (CryptogramUtil.Decrypt(user.Password).Equals(password)) return; if (CryptogramUtil.Decrypt(user.Password).Equals(password))
return Task.CompletedTask;
} }
arg.ReasonCode = MqttConnectReasonCode.BadUserNameOrPassword; arg.ReasonCode = MqttConnectReasonCode.BadUserNameOrPassword;
Log($"客户端验证客户端ID=【{arg.ClientId}】用户名或密码验证错误 {DateTime.Now} "); Logging($"客户端验证客户端ID=【{arg.ClientId}】用户名或密码验证错误 {DateTime.Now} ");
return Task.CompletedTask;
} }
} }

View File

@ -5,86 +5,116 @@
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任! // 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
using MQTTnet.Server; using MQTTnet.Server;
using MQTTnet;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using MQTTnet.Protocol;
using Furion.Logging.Extensions;
using Furion.HttpRemote;
namespace Admin.NET.Core; namespace Admin.NET.Core;
/// <summary> /// <summary>
/// Mqtt事件拦截器 /// MQTT 事件拦截器
/// </summary> /// </summary>
/// <remarks> public class MqttEventInterceptor
/// 为了让底层的 Mqtt 代码与业务层代码分离,应该不同的业务继函 MqttEventHandler 类,实现自己的代码后
/// 在 Startup.cs 的 Configure 函数中,调用 MqttHostedService 对象的 RegistMqttEventHandler 函数,来注册自己的事件处理器
/// “业务相关的代码千万不要写在 MqttHostedService 中”
/// </remarks>
public class MqttEventHandler
{ {
/// <summary> /// <summary>
/// 排序,数据越大越先执行 /// 数值越大越先执行
/// </summary> /// </summary>
public int Order = 0; public int Order = 0;
protected void Log(string msg) /// <summary>
{ /// 启动后事件
var mqttOptions = App.GetOptions<MqttOptions>(); /// </summary>
if (mqttOptions.ConsoleOutput) /// <param name="arg"></param>
Console.WriteLine(msg); /// <returns></returns>
if (mqttOptions.Logging)
msg.LogDebug();
}
public virtual async Task ValidatingConnectionAsync(ValidatingConnectionEventArgs arg)
{
}
public virtual async Task StartedAsync(EventArgs arg) public virtual async Task StartedAsync(EventArgs arg)
{ {
} await Task.CompletedTask;
public virtual async Task StoppedAsync(EventArgs arg)
{
} }
/// <summary> /// <summary>
/// 客户端发布的数据 /// 关闭后事件
/// </summary>
/// <param name="arg"></param>
/// <returns></returns>
public virtual async Task StoppedAsync(EventArgs arg)
{
await Task.CompletedTask;
}
/// <summary>
/// 客户端验证事件
/// </summary>
/// <param name="arg"></param>
/// <returns></returns>
public virtual async Task ValidatingConnectionAsync(ValidatingConnectionEventArgs arg)
{
await Task.CompletedTask;
}
/// <summary>
/// 客户端连接事件
/// </summary>
/// <param name="arg"></param>
/// <returns></returns>
public virtual async Task ClientConnectedAsync(ClientConnectedEventArgs arg)
{
await Task.CompletedTask;
}
/// <summary>
/// 客户端断开事件
/// </summary>
/// <param name="arg"></param>
/// <returns></returns>
public virtual async Task ClientDisconnectedAsync(ClientDisconnectedEventArgs arg)
{
await Task.CompletedTask;
}
/// <summary>
/// 订阅主题事件
/// </summary>
/// <param name="arg"></param>
/// <returns></returns>
public virtual async Task ClientSubscribedTopicAsync(ClientSubscribedTopicEventArgs arg)
{
await Task.CompletedTask;
}
/// <summary>
/// 取消订阅事件
/// </summary>
/// <param name="arg"></param>
/// <returns></returns>
public virtual async Task ClientUnsubscribedTopicAsync(ClientUnsubscribedTopicEventArgs arg)
{
await Task.CompletedTask;
}
/// <summary>
/// 拦截发布的消息事件
/// </summary> /// </summary>
/// <param name="arg"></param> /// <param name="arg"></param>
/// <returns></returns> /// <returns></returns>
public virtual async Task InterceptingPublishAsync(InterceptingPublishEventArgs arg) public virtual async Task InterceptingPublishAsync(InterceptingPublishEventArgs arg)
{ {
await Task.CompletedTask;
} }
/// <summary> /// <summary>
/// 没有客户端接收的数据 /// 未被消费的消息事件
/// </summary> /// </summary>
/// <param name="arg"></param> /// <param name="arg"></param>
/// <returns></returns> /// <returns></returns>
public virtual async Task ApplicationMessageNotConsumedAsync(ApplicationMessageNotConsumedEventArgs arg) public virtual async Task ApplicationMessageNotConsumedAsync(ApplicationMessageNotConsumedEventArgs arg)
{ {
await Task.CompletedTask;
} }
public virtual async Task ClientSubscribedTopicAsync(ClientSubscribedTopicEventArgs arg) /// <summary>
{ /// 输出日志事件
} /// </summary>
public virtual async Task ClientUnsubscribedTopicAsync(ClientUnsubscribedTopicEventArgs arg) /// <param name="msg"></param>
{ protected static void Logging(string msg)
}
public virtual async Task ClientDisconnectedAsync(ClientDisconnectedEventArgs arg)
{
}
public virtual async Task ClientConnectedAsync(ClientConnectedEventArgs arg)
{ {
if (!App.GetOptions<MqttOptions>().Logging) return;
LoggingWriter.LogInformation(msg);
} }
} }

View File

@ -11,31 +11,11 @@ namespace Admin.NET.Core;
/// </summary> /// </summary>
public sealed class MqttOptions : IConfigurableOptions public sealed class MqttOptions : IConfigurableOptions
{ {
/// <summary>
/// 服务器主动发布时用的ClientId
/// </summary>
public string MqttServerId { get; set; }
/// <summary> /// <summary>
/// 是否启用 /// 是否启用
/// </summary> /// </summary>
public bool Enabled { get; set; } public bool Enabled { get; set; }
/// <summary>
/// 输出文件日志
/// </summary>
public bool Logging { get; set; }
/// <summary>
/// 控制台输出
/// </summary>
public bool ConsoleOutput { get; set; }
/// <summary>
/// ConnectionBacklog
/// </summary>
public int ConnectionBacklog { get; set; }
/// <summary> /// <summary>
/// 端口 /// 端口
/// </summary> /// </summary>
@ -45,4 +25,19 @@ public sealed class MqttOptions : IConfigurableOptions
/// IP地址 /// IP地址
/// </summary> /// </summary>
public string IPAddress { get; set; } public string IPAddress { get; set; }
/// <summary>
/// 最大连接数
/// </summary>
public int ConnectionBacklog { get; set; }
/// <summary>
/// 服务器主动发消息时的ClientId
/// </summary>
public string MqttServerId { get; set; }
/// <summary>
/// 输出日志
/// </summary>
public bool Logging { get; set; }
} }

View File

@ -4,16 +4,20 @@
// //
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任! // 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Admin.NET.Core; namespace Admin.NET.Core;
/// <summary>
/// 发布主题消息
/// </summary>
public class PublicMessageInput public class PublicMessageInput
{ {
/// <summary>
/// 主题名称
/// </summary>
public string Topic { get; set; } public string Topic { get; set; }
/// <summary>
/// 消息内容
/// </summary>
public string Message { get; set; } public string Message { get; set; }
} }

View File

@ -28,15 +28,14 @@ public class SysMqttService() : IDynamicApiController, ITransient
} }
/// <summary> /// <summary>
/// 发布主题 🔖 /// 发布主题消息 🔖
/// </summary> /// </summary>
/// <param name="input"></param> /// <param name="input"></param>
/// <returns></returns> /// <returns></returns>
[AllowAnonymous] [DisplayName("发布主题消息")]
[DisplayName("发布主题")]
public async Task PublicMessage(PublicMessageInput input) public async Task PublicMessage(PublicMessageInput input)
{ {
MqttHostedService mqttHostedService = App.GetRequiredService<MqttHostedService>(); var mqttHostedService = App.GetRequiredService<MqttHostedService>();
mqttHostedService.PublicMessage(input.Topic, input.Message); await mqttHostedService.PublicMessageAsync(input.Topic, input.Message);
} }
} }

View File

@ -22,7 +22,6 @@ using Microsoft.AspNetCore.ResponseCompression;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders; using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using MQTTnet.AspNetCore; using MQTTnet.AspNetCore;
using Newtonsoft.Json; using Newtonsoft.Json;
using OnceMi.AspNetCore.OSS; using OnceMi.AspNetCore.OSS;
@ -108,7 +107,8 @@ public class Startup : AppStartup
// setting.MetadataPropertyHandling = MetadataPropertyHandling.Ignore; // 解决DateTimeOffset异常 // setting.MetadataPropertyHandling = MetadataPropertyHandling.Ignore; // 解决DateTimeOffset异常
// setting.DateParseHandling = DateParseHandling.None; // 解决DateTimeOffset异常 // setting.DateParseHandling = DateParseHandling.None; // 解决DateTimeOffset异常
// setting.Converters.Add(new IsoDateTimeConverter { DateTimeStyles = DateTimeStyles.AssumeUniversal }); // 解决DateTimeOffset异常 // setting.Converters.Add(new IsoDateTimeConverter { DateTimeStyles = DateTimeStyles.AssumeUniversal }); // 解决DateTimeOffset异常
}; }
;
services.AddControllersWithViews() services.AddControllersWithViews()
.AddAppLocalization() .AddAppLocalization()
@ -412,29 +412,22 @@ public class Startup : AppStartup
} }
}); });
IOptions<MqttOptions> mqttOptions = App.GetRequiredService<IOptions<MqttOptions>>(); var mqttOptions = App.GetConfig<MqttOptions>("Mqtt", true);
app.UseEndpoints(endpoints => app.UseEndpoints(endpoints =>
{ {
// 注册集线器 // 注册集线器
endpoints.MapHubs(); endpoints.MapHubs();
// 注册路由
endpoints.MapControllerRoute( endpoints.MapControllerRoute(
name: "default", name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}"); pattern: "{controller=Home}/{action=Index}/{id?}");
if (mqttOptions.Value.Enabled) // 注册 MQTT 支持 WebSocket
if (mqttOptions.Enabled)
{ {
endpoints.MapConnectionHandler<MqttConnectionHandler>( endpoints.MapConnectionHandler<MqttConnectionHandler>("/mqtt",
"/mqtt",
httpConnectionDispatcherOptions => httpConnectionDispatcherOptions.WebSockets.SubProtocolSelector = httpConnectionDispatcherOptions => httpConnectionDispatcherOptions.WebSockets.SubProtocolSelector =
protocolList => protocolList.FirstOrDefault() ?? string.Empty); protocolList => protocolList.FirstOrDefault() ?? string.Empty);
} }
}); });
if (mqttOptions.Value.Enabled)
{
// [以下是验证的示例] 注册自己业务的 Mqtt 处理器,如果有不同的认证方式,要把以下这句注释掉
//MqttHostedService.RegistMqttEventHandler(new MqttEventHandlerForAdminNet(), int.MaxValue);
}
} }
} }

View File

@ -2,7 +2,7 @@
"name": "admin.net.pro", "name": "admin.net.pro",
"type": "module", "type": "module",
"version": "2.4.33", "version": "2.4.33",
"lastBuildTime": "2025.02.20", "lastBuildTime": "2025.02.23",
"description": "Admin.NET 站在巨人肩膀上的 .NET 通用权限开发框架", "description": "Admin.NET 站在巨人肩膀上的 .NET 通用权限开发框架",
"author": "zuohuaijun", "author": "zuohuaijun",
"license": "MIT", "license": "MIT",
@ -18,8 +18,8 @@
}, },
"dependencies": { "dependencies": {
"@element-plus/icons-vue": "^2.3.1", "@element-plus/icons-vue": "^2.3.1",
"@logicflow/core": "^2.0.10", "@logicflow/core": "^2.0.11",
"@logicflow/extension": "^2.0.14", "@logicflow/extension": "^2.0.15",
"@microsoft/signalr": "^8.0.7", "@microsoft/signalr": "^8.0.7",
"@vue-office/docx": "^1.6.2", "@vue-office/docx": "^1.6.2",
"@vue-office/excel": "^1.7.14", "@vue-office/excel": "^1.7.14",
@ -36,7 +36,7 @@
"echarts": "^5.6.0", "echarts": "^5.6.0",
"echarts-gl": "^2.0.9", "echarts-gl": "^2.0.9",
"echarts-wordcloud": "^2.1.0", "echarts-wordcloud": "^2.1.0",
"element-plus": "^2.9.4", "element-plus": "^2.9.5",
"exceljs": "^4.4.0", "exceljs": "^4.4.0",
"ezuikit-js": "^8.1.6", "ezuikit-js": "^8.1.6",
"gcoord": "^1.0.7", "gcoord": "^1.0.7",
@ -45,7 +45,7 @@
"jsplumb": "^2.15.6", "jsplumb": "^2.15.6",
"jwchat": "^2.0.3", "jwchat": "^2.0.3",
"lodash-es": "^4.17.21", "lodash-es": "^4.17.21",
"md-editor-v3": "^5.2.3", "md-editor-v3": "^5.3.2",
"mitt": "^3.0.1", "mitt": "^3.0.1",
"monaco-editor": "^0.52.2", "monaco-editor": "^0.52.2",
"mqtt": "^5.10.3", "mqtt": "^5.10.3",
@ -74,7 +74,7 @@
"vue-router": "^4.5.0", "vue-router": "^4.5.0",
"vue-signature-pad": "^3.0.2", "vue-signature-pad": "^3.0.2",
"vue3-tree-org": "^4.2.2", "vue3-tree-org": "^4.2.2",
"vxe-pc-ui": "^4.3.91", "vxe-pc-ui": "^4.3.95",
"vxe-table": "^4.10.0", "vxe-table": "^4.10.0",
"vxe-table-plugin-element": "^4.0.4", "vxe-table-plugin-element": "^4.0.4",
"vxe-table-plugin-export-xlsx": "^4.0.7", "vxe-table-plugin-export-xlsx": "^4.0.7",
@ -94,11 +94,11 @@
"@vitejs/plugin-vue-jsx": "^4.1.1", "@vitejs/plugin-vue-jsx": "^4.1.1",
"@vue/compiler-sfc": "^3.5.13", "@vue/compiler-sfc": "^3.5.13",
"code-inspector-plugin": "^0.20.0", "code-inspector-plugin": "^0.20.0",
"eslint": "^9.20.1", "eslint": "^9.21.0",
"eslint-plugin-vue": "^9.32.0", "eslint-plugin-vue": "^9.32.0",
"globals": "^15.15.0", "globals": "^16.0.0",
"less": "^4.2.2", "less": "^4.2.2",
"prettier": "^3.5.1", "prettier": "^3.5.2",
"rollup-plugin-visualizer": "^5.14.0", "rollup-plugin-visualizer": "^5.14.0",
"sass": "^1.85.0", "sass": "^1.85.0",
"terser": "^5.39.0", "terser": "^5.39.0",

View File

@ -38,6 +38,7 @@ export * from './apis/sys-log-op-api';
export * from './apis/sys-log-vis-api'; export * from './apis/sys-log-vis-api';
export * from './apis/sys-menu-api'; export * from './apis/sys-menu-api';
export * from './apis/sys-message-api'; export * from './apis/sys-message-api';
export * from './apis/sys-mqtt-api';
export * from './apis/sys-notice-api'; export * from './apis/sys-notice-api';
export * from './apis/sys-oauth-api'; export * from './apis/sys-oauth-api';
export * from './apis/sys-oauth-user-api'; export * from './apis/sys-oauth-user-api';

View File

@ -77,6 +77,49 @@ export const SysEnumApiAxiosParamCreator = function (configuration?: Configurati
options: localVarRequestOptions, options: localVarRequestOptions,
}; };
}, },
/**
*
* @summary
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
apiSysEnumEnumToDictPost: async (options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
const localVarPath = `/api/sysEnum/enumToDict`;
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, 'https://example.com');
let baseOptions;
if (configuration) {
baseOptions = configuration.baseOptions;
}
const localVarRequestOptions :AxiosRequestConfig = { method: 'POST', ...baseOptions, ...options};
const localVarHeaderParameter = {} as any;
const localVarQueryParameter = {} as any;
// authentication Bearer required
// http bearer authentication required
if (configuration && configuration.accessToken) {
const accessToken = typeof configuration.accessToken === 'function'
? await configuration.accessToken()
: await configuration.accessToken;
localVarHeaderParameter["Authorization"] = "Bearer " + accessToken;
}
const query = new URLSearchParams(localVarUrlObj.search);
for (const key in localVarQueryParameter) {
query.set(key, localVarQueryParameter[key]);
}
for (const key in options.params) {
query.set(key, options.params[key]);
}
localVarUrlObj.search = (new URLSearchParams(query)).toString();
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
return {
url: localVarUrlObj.pathname + localVarUrlObj.search + localVarUrlObj.hash,
options: localVarRequestOptions,
};
},
/** /**
* *
* @summary 🔖 * @summary 🔖
@ -143,6 +186,19 @@ export const SysEnumApiFp = function(configuration?: Configuration) {
return axios.request(axiosRequestArgs); return axios.request(axiosRequestArgs);
}; };
}, },
/**
*
* @summary
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async apiSysEnumEnumToDictPost(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<void>>> {
const localVarAxiosArgs = await SysEnumApiAxiosParamCreator(configuration).apiSysEnumEnumToDictPost(options);
return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
return axios.request(axiosRequestArgs);
};
},
/** /**
* *
* @summary 🔖 * @summary 🔖
@ -175,6 +231,15 @@ export const SysEnumApiFactory = function (configuration?: Configuration, basePa
async apiSysEnumEnumDataListGet(enumName: string, options?: AxiosRequestConfig): Promise<AxiosResponse<AdminNETResultListEnumEntity>> { async apiSysEnumEnumDataListGet(enumName: string, options?: AxiosRequestConfig): Promise<AxiosResponse<AdminNETResultListEnumEntity>> {
return SysEnumApiFp(configuration).apiSysEnumEnumDataListGet(enumName, options).then((request) => request(axios, basePath)); return SysEnumApiFp(configuration).apiSysEnumEnumDataListGet(enumName, options).then((request) => request(axios, basePath));
}, },
/**
*
* @summary
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async apiSysEnumEnumToDictPost(options?: AxiosRequestConfig): Promise<AxiosResponse<void>> {
return SysEnumApiFp(configuration).apiSysEnumEnumToDictPost(options).then((request) => request(axios, basePath));
},
/** /**
* *
* @summary 🔖 * @summary 🔖
@ -205,6 +270,16 @@ export class SysEnumApi extends BaseAPI {
public async apiSysEnumEnumDataListGet(enumName: string, options?: AxiosRequestConfig) : Promise<AxiosResponse<AdminNETResultListEnumEntity>> { public async apiSysEnumEnumDataListGet(enumName: string, options?: AxiosRequestConfig) : Promise<AxiosResponse<AdminNETResultListEnumEntity>> {
return SysEnumApiFp(this.configuration).apiSysEnumEnumDataListGet(enumName, options).then((request) => request(this.axios, this.basePath)); return SysEnumApiFp(this.configuration).apiSysEnumEnumDataListGet(enumName, options).then((request) => request(this.axios, this.basePath));
} }
/**
*
* @summary
* @param {*} [options] Override http request option.
* @throws {RequiredError}
* @memberof SysEnumApi
*/
public async apiSysEnumEnumToDictPost(options?: AxiosRequestConfig) : Promise<AxiosResponse<void>> {
return SysEnumApiFp(this.configuration).apiSysEnumEnumToDictPost(options).then((request) => request(this.axios, this.basePath));
}
/** /**
* *
* @summary 🔖 * @summary 🔖

View File

@ -0,0 +1,214 @@
/* tslint:disable */
/* eslint-disable */
/**
* Admin.NET
* .NET <br/><u><b><font color='FF0000'> 👮</font></b></u>
*
* OpenAPI spec version: 1.0.0
*
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/
import globalAxios, { AxiosResponse, AxiosInstance, AxiosRequestConfig } from 'axios';
import { Configuration } from '../configuration';
// Some imports not used depending on template conditions
// @ts-ignore
import { BASE_PATH, COLLECTION_FORMATS, RequestArgs, BaseAPI, RequiredError } from '../base';
import { AdminNETResultIListMqttClientStatus } from '../models';
import { PublicMessageInput } from '../models';
/**
* SysMqttApi - axios parameter creator
* @export
*/
export const SysMqttApiAxiosParamCreator = function (configuration?: Configuration) {
return {
/**
*
* @summary 🔖
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
apiSysMqttClientsGet: async (options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
const localVarPath = `/api/sysMqtt/clients`;
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, 'https://example.com');
let baseOptions;
if (configuration) {
baseOptions = configuration.baseOptions;
}
const localVarRequestOptions :AxiosRequestConfig = { method: 'GET', ...baseOptions, ...options};
const localVarHeaderParameter = {} as any;
const localVarQueryParameter = {} as any;
// authentication Bearer required
// http bearer authentication required
if (configuration && configuration.accessToken) {
const accessToken = typeof configuration.accessToken === 'function'
? await configuration.accessToken()
: await configuration.accessToken;
localVarHeaderParameter["Authorization"] = "Bearer " + accessToken;
}
const query = new URLSearchParams(localVarUrlObj.search);
for (const key in localVarQueryParameter) {
query.set(key, localVarQueryParameter[key]);
}
for (const key in options.params) {
query.set(key, options.params[key]);
}
localVarUrlObj.search = (new URLSearchParams(query)).toString();
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
return {
url: localVarUrlObj.pathname + localVarUrlObj.search + localVarUrlObj.hash,
options: localVarRequestOptions,
};
},
/**
*
* @summary 🔖
* @param {PublicMessageInput} [body]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
apiSysMqttPublicMessagePost: async (body?: PublicMessageInput, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
const localVarPath = `/api/sysMqtt/publicMessage`;
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, 'https://example.com');
let baseOptions;
if (configuration) {
baseOptions = configuration.baseOptions;
}
const localVarRequestOptions :AxiosRequestConfig = { method: 'POST', ...baseOptions, ...options};
const localVarHeaderParameter = {} as any;
const localVarQueryParameter = {} as any;
// authentication Bearer required
// http bearer authentication required
if (configuration && configuration.accessToken) {
const accessToken = typeof configuration.accessToken === 'function'
? await configuration.accessToken()
: await configuration.accessToken;
localVarHeaderParameter["Authorization"] = "Bearer " + accessToken;
}
localVarHeaderParameter['Content-Type'] = 'application/json-patch+json';
const query = new URLSearchParams(localVarUrlObj.search);
for (const key in localVarQueryParameter) {
query.set(key, localVarQueryParameter[key]);
}
for (const key in options.params) {
query.set(key, options.params[key]);
}
localVarUrlObj.search = (new URLSearchParams(query)).toString();
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
const needsSerialization = (typeof body !== "string") || localVarRequestOptions.headers['Content-Type'] === 'application/json';
localVarRequestOptions.data = needsSerialization ? JSON.stringify(body !== undefined ? body : {}) : (body || "");
return {
url: localVarUrlObj.pathname + localVarUrlObj.search + localVarUrlObj.hash,
options: localVarRequestOptions,
};
},
}
};
/**
* SysMqttApi - functional programming interface
* @export
*/
export const SysMqttApiFp = function(configuration?: Configuration) {
return {
/**
*
* @summary 🔖
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async apiSysMqttClientsGet(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<AdminNETResultIListMqttClientStatus>>> {
const localVarAxiosArgs = await SysMqttApiAxiosParamCreator(configuration).apiSysMqttClientsGet(options);
return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
return axios.request(axiosRequestArgs);
};
},
/**
*
* @summary 🔖
* @param {PublicMessageInput} [body]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async apiSysMqttPublicMessagePost(body?: PublicMessageInput, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<void>>> {
const localVarAxiosArgs = await SysMqttApiAxiosParamCreator(configuration).apiSysMqttPublicMessagePost(body, options);
return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
return axios.request(axiosRequestArgs);
};
},
}
};
/**
* SysMqttApi - factory interface
* @export
*/
export const SysMqttApiFactory = function (configuration?: Configuration, basePath?: string, axios?: AxiosInstance) {
return {
/**
*
* @summary 🔖
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async apiSysMqttClientsGet(options?: AxiosRequestConfig): Promise<AxiosResponse<AdminNETResultIListMqttClientStatus>> {
return SysMqttApiFp(configuration).apiSysMqttClientsGet(options).then((request) => request(axios, basePath));
},
/**
*
* @summary 🔖
* @param {PublicMessageInput} [body]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async apiSysMqttPublicMessagePost(body?: PublicMessageInput, options?: AxiosRequestConfig): Promise<AxiosResponse<void>> {
return SysMqttApiFp(configuration).apiSysMqttPublicMessagePost(body, options).then((request) => request(axios, basePath));
},
};
};
/**
* SysMqttApi - object-oriented interface
* @export
* @class SysMqttApi
* @extends {BaseAPI}
*/
export class SysMqttApi extends BaseAPI {
/**
*
* @summary 🔖
* @param {*} [options] Override http request option.
* @throws {RequiredError}
* @memberof SysMqttApi
*/
public async apiSysMqttClientsGet(options?: AxiosRequestConfig) : Promise<AxiosResponse<AdminNETResultIListMqttClientStatus>> {
return SysMqttApiFp(this.configuration).apiSysMqttClientsGet(options).then((request) => request(this.axios, this.basePath));
}
/**
*
* @summary 🔖
* @param {PublicMessageInput} [body]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
* @memberof SysMqttApi
*/
public async apiSysMqttPublicMessagePost(body?: PublicMessageInput, options?: AxiosRequestConfig) : Promise<AxiosResponse<void>> {
return SysMqttApiFp(this.configuration).apiSysMqttPublicMessagePost(body, options).then((request) => request(this.axios, this.basePath));
}
}

View File

@ -74,6 +74,49 @@ export const SysOnlineUserApiAxiosParamCreator = function (configuration?: Confi
options: localVarRequestOptions, options: localVarRequestOptions,
}; };
}, },
/**
*
* @summary 线
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
apiSysOnlineUserOnlinePost: async (options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
const localVarPath = `/api/sysOnlineUser/online`;
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, 'https://example.com');
let baseOptions;
if (configuration) {
baseOptions = configuration.baseOptions;
}
const localVarRequestOptions :AxiosRequestConfig = { method: 'POST', ...baseOptions, ...options};
const localVarHeaderParameter = {} as any;
const localVarQueryParameter = {} as any;
// authentication Bearer required
// http bearer authentication required
if (configuration && configuration.accessToken) {
const accessToken = typeof configuration.accessToken === 'function'
? await configuration.accessToken()
: await configuration.accessToken;
localVarHeaderParameter["Authorization"] = "Bearer " + accessToken;
}
const query = new URLSearchParams(localVarUrlObj.search);
for (const key in localVarQueryParameter) {
query.set(key, localVarQueryParameter[key]);
}
for (const key in options.params) {
query.set(key, options.params[key]);
}
localVarUrlObj.search = (new URLSearchParams(query)).toString();
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
return {
url: localVarUrlObj.pathname + localVarUrlObj.search + localVarUrlObj.hash,
options: localVarRequestOptions,
};
},
/** /**
* *
* @summary 线 🔖 * @summary 线 🔖
@ -145,6 +188,19 @@ export const SysOnlineUserApiFp = function(configuration?: Configuration) {
return axios.request(axiosRequestArgs); return axios.request(axiosRequestArgs);
}; };
}, },
/**
*
* @summary 线
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async apiSysOnlineUserOnlinePost(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<void>>> {
const localVarAxiosArgs = await SysOnlineUserApiAxiosParamCreator(configuration).apiSysOnlineUserOnlinePost(options);
return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
return axios.request(axiosRequestArgs);
};
},
/** /**
* *
* @summary 线 🔖 * @summary 线 🔖
@ -178,6 +234,15 @@ export const SysOnlineUserApiFactory = function (configuration?: Configuration,
async apiSysOnlineUserForceOfflinePost(body?: SysOnlineUser, options?: AxiosRequestConfig): Promise<AxiosResponse<void>> { async apiSysOnlineUserForceOfflinePost(body?: SysOnlineUser, options?: AxiosRequestConfig): Promise<AxiosResponse<void>> {
return SysOnlineUserApiFp(configuration).apiSysOnlineUserForceOfflinePost(body, options).then((request) => request(axios, basePath)); return SysOnlineUserApiFp(configuration).apiSysOnlineUserForceOfflinePost(body, options).then((request) => request(axios, basePath));
}, },
/**
*
* @summary 线
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async apiSysOnlineUserOnlinePost(options?: AxiosRequestConfig): Promise<AxiosResponse<void>> {
return SysOnlineUserApiFp(configuration).apiSysOnlineUserOnlinePost(options).then((request) => request(axios, basePath));
},
/** /**
* *
* @summary 线 🔖 * @summary 线 🔖
@ -209,6 +274,16 @@ export class SysOnlineUserApi extends BaseAPI {
public async apiSysOnlineUserForceOfflinePost(body?: SysOnlineUser, options?: AxiosRequestConfig) : Promise<AxiosResponse<void>> { public async apiSysOnlineUserForceOfflinePost(body?: SysOnlineUser, options?: AxiosRequestConfig) : Promise<AxiosResponse<void>> {
return SysOnlineUserApiFp(this.configuration).apiSysOnlineUserForceOfflinePost(body, options).then((request) => request(this.axios, this.basePath)); return SysOnlineUserApiFp(this.configuration).apiSysOnlineUserForceOfflinePost(body, options).then((request) => request(this.axios, this.basePath));
} }
/**
*
* @summary 线
* @param {*} [options] Override http request option.
* @throws {RequiredError}
* @memberof SysOnlineUserApi
*/
public async apiSysOnlineUserOnlinePost(options?: AxiosRequestConfig) : Promise<AxiosResponse<void>> {
return SysOnlineUserApiFp(this.configuration).apiSysOnlineUserOnlinePost(options).then((request) => request(this.axios, this.basePath));
}
/** /**
* *
* @summary 线 🔖 * @summary 线 🔖

View File

@ -0,0 +1,53 @@
/* tslint:disable */
/* eslint-disable */
/**
* Admin.NET
* .NET <br/><u><b><font color='FF0000'> 👮</font></b></u>
*
* OpenAPI spec version: 1.0.0
*
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/
/**
*
* @export
* @enum {string}
*/
export enum AddressFamily {
NUMBER_0 = 0,
NUMBER_1 = 1,
NUMBER_2 = 2,
NUMBER_3 = 3,
NUMBER_4 = 4,
NUMBER_5 = 5,
NUMBER_6 = 6,
NUMBER_7 = 7,
NUMBER_8 = 8,
NUMBER_9 = 9,
NUMBER_10 = 10,
NUMBER_11 = 11,
NUMBER_12 = 12,
NUMBER_13 = 13,
NUMBER_14 = 14,
NUMBER_15 = 15,
NUMBER_16 = 16,
NUMBER_17 = 17,
NUMBER_18 = 18,
NUMBER_19 = 19,
NUMBER_21 = 21,
NUMBER_22 = 22,
NUMBER_23 = 23,
NUMBER_24 = 24,
NUMBER_25 = 25,
NUMBER_26 = 26,
NUMBER_28 = 28,
NUMBER_29 = 29,
NUMBER_65536 = 65536,
NUMBER_65537 = 65537,
NUMBER_MINUS_1 = -1
}

View File

@ -0,0 +1,71 @@
/* tslint:disable */
/* eslint-disable */
/**
* Admin.NET
* .NET <br/><u><b><font color='FF0000'> 👮</font></b></u>
*
* OpenAPI spec version: 1.0.0
*
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/
import { MqttClientStatus } from './mqtt-client-status';
/**
*
*
* @export
* @interface AdminNETResultIListMqttClientStatus
*/
export interface AdminNETResultIListMqttClientStatus {
/**
*
*
* @type {number}
* @memberof AdminNETResultIListMqttClientStatus
*/
code?: number;
/**
* successwarningerror
*
* @type {string}
* @memberof AdminNETResultIListMqttClientStatus
*/
type?: string | null;
/**
*
*
* @type {string}
* @memberof AdminNETResultIListMqttClientStatus
*/
message?: string | null;
/**
*
*
* @type {Array<MqttClientStatus>}
* @memberof AdminNETResultIListMqttClientStatus
*/
result?: Array<MqttClientStatus> | null;
/**
*
*
* @type {any}
* @memberof AdminNETResultIListMqttClientStatus
*/
extras?: any | null;
/**
*
*
* @type {Date}
* @memberof AdminNETResultIListMqttClientStatus
*/
time?: Date;
}

View File

@ -0,0 +1,29 @@
/* tslint:disable */
/* eslint-disable */
/**
* Admin.NET
* .NET <br/><u><b><font color='FF0000'> 👮</font></b></u>
*
* OpenAPI spec version: 1.0.0
*
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/
import { AddressFamily } from './address-family';
/**
*
*
* @export
* @interface EndPoint
*/
export interface EndPoint {
/**
* @type {AddressFamily}
* @memberof EndPoint
*/
addressFamily?: AddressFamily;
}

View File

@ -21,6 +21,7 @@ export * from './add-sys-ldap-input';
export * from './add-tenant-input'; export * from './add-tenant-input';
export * from './add-upgrade-input'; export * from './add-upgrade-input';
export * from './add-user-input'; export * from './add-user-input';
export * from './address-family';
export * from './admin-netresult-boolean'; export * from './admin-netresult-boolean';
export * from './admin-netresult-captcha-output'; export * from './admin-netresult-captcha-output';
export * from './admin-netresult-create-pay-transaction-native-output'; export * from './admin-netresult-create-pay-transaction-native-output';
@ -34,6 +35,7 @@ export * from './admin-netresult-grant-role-output';
export * from './admin-netresult-iaction-result'; export * from './admin-netresult-iaction-result';
export * from './admin-netresult-idisposable'; export * from './admin-netresult-idisposable';
export * from './admin-netresult-ienumerable-entity-info'; export * from './admin-netresult-ienumerable-entity-info';
export * from './admin-netresult-ilist-mqtt-client-status';
export * from './admin-netresult-int32'; export * from './admin-netresult-int32';
export * from './admin-netresult-int64'; export * from './admin-netresult-int64';
export * from './admin-netresult-jobject'; export * from './admin-netresult-jobject';
@ -210,6 +212,7 @@ export * from './delete-user-input';
export * from './dict-data-input'; export * from './dict-data-input';
export * from './dict-type-input'; export * from './dict-type-input';
export * from './digit-shapes'; export * from './digit-shapes';
export * from './end-point';
export * from './entity-column-info'; export * from './entity-column-info';
export * from './entity-info'; export * from './entity-info';
export * from './enum-entity'; export * from './enum-entity';
@ -276,6 +279,9 @@ export * from './method-impl-attributes';
export * from './method-info'; export * from './method-info';
export * from './module'; export * from './module';
export * from './module-handle'; export * from './module-handle';
export * from './mqtt-client-status';
export * from './mqtt-protocol-version';
export * from './mqtt-session-status';
export * from './navigate'; export * from './navigate';
export * from './notice-input'; export * from './notice-input';
export * from './notice-status-enum'; export * from './notice-status-enum';
@ -322,6 +328,7 @@ export * from './print-type-enum';
export * from './promotion'; export * from './promotion';
export * from './property-attributes'; export * from './property-attributes';
export * from './property-info'; export * from './property-info';
export * from './public-message-input';
export * from './query-region-input'; export * from './query-region-input';
export * from './refund-request-input'; export * from './refund-request-input';
export * from './reset-pwd-user-input'; export * from './reset-pwd-user-input';

View File

@ -0,0 +1,115 @@
/* tslint:disable */
/* eslint-disable */
/**
* Admin.NET
* .NET <br/><u><b><font color='FF0000'> 👮</font></b></u>
*
* OpenAPI spec version: 1.0.0
*
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/
import { EndPoint } from './end-point';
import { MqttProtocolVersion } from './mqtt-protocol-version';
import { MqttSessionStatus } from './mqtt-session-status';
/**
*
*
* @export
* @interface MqttClientStatus
*/
export interface MqttClientStatus {
/**
* @type {number}
* @memberof MqttClientStatus
*/
bytesReceived?: number;
/**
* @type {number}
* @memberof MqttClientStatus
*/
bytesSent?: number;
/**
* @type {Date}
* @memberof MqttClientStatus
*/
connectedTimestamp?: Date;
/**
* @type {EndPoint}
* @memberof MqttClientStatus
*/
remoteEndPoint?: EndPoint;
/**
* @type {string}
* @memberof MqttClientStatus
*/
endpoint?: string | null;
/**
* @type {string}
* @memberof MqttClientStatus
*/
id?: string | null;
/**
* @type {Date}
* @memberof MqttClientStatus
*/
lastNonKeepAlivePacketReceivedTimestamp?: Date;
/**
* @type {Date}
* @memberof MqttClientStatus
*/
lastPacketReceivedTimestamp?: Date;
/**
* @type {Date}
* @memberof MqttClientStatus
*/
lastPacketSentTimestamp?: Date;
/**
* @type {MqttProtocolVersion}
* @memberof MqttClientStatus
*/
protocolVersion?: MqttProtocolVersion;
/**
* @type {number}
* @memberof MqttClientStatus
*/
receivedApplicationMessagesCount?: number;
/**
* @type {number}
* @memberof MqttClientStatus
*/
receivedPacketsCount?: number;
/**
* @type {number}
* @memberof MqttClientStatus
*/
sentApplicationMessagesCount?: number;
/**
* @type {number}
* @memberof MqttClientStatus
*/
sentPacketsCount?: number;
/**
* @type {MqttSessionStatus}
* @memberof MqttClientStatus
*/
session?: MqttSessionStatus;
}

View File

@ -0,0 +1,26 @@
/* tslint:disable */
/* eslint-disable */
/**
* Admin.NET
* .NET <br/><u><b><font color='FF0000'> 👮</font></b></u>
*
* OpenAPI spec version: 1.0.0
*
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/
/**
*
* @export
* @enum {string}
*/
export enum MqttProtocolVersion {
NUMBER_0 = 0,
NUMBER_3 = 3,
NUMBER_4 = 4,
NUMBER_5 = 5
}

View File

@ -0,0 +1,58 @@
/* tslint:disable */
/* eslint-disable */
/**
* Admin.NET
* .NET <br/><u><b><font color='FF0000'> 👮</font></b></u>
*
* OpenAPI spec version: 1.0.0
*
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/
/**
*
*
* @export
* @interface MqttSessionStatus
*/
export interface MqttSessionStatus {
/**
* @type {Date}
* @memberof MqttSessionStatus
*/
createdTimestamp?: Date;
/**
* @type {Date}
* @memberof MqttSessionStatus
*/
disconnectedTimestamp?: Date | null;
/**
* @type {number}
* @memberof MqttSessionStatus
*/
expiryInterval?: number;
/**
* @type {string}
* @memberof MqttSessionStatus
*/
id?: string | null;
/**
* @type {{ [key: string]: any; }}
* @memberof MqttSessionStatus
*/
items?: { [key: string]: any; } | null;
/**
* @type {number}
* @memberof MqttSessionStatus
*/
pendingApplicationMessagesCount?: number;
}

View File

@ -0,0 +1,38 @@
/* tslint:disable */
/* eslint-disable */
/**
* Admin.NET
* .NET <br/><u><b><font color='FF0000'> 👮</font></b></u>
*
* OpenAPI spec version: 1.0.0
*
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/
/**
*
*
* @export
* @interface PublicMessageInput
*/
export interface PublicMessageInput {
/**
*
*
* @type {string}
* @memberof PublicMessageInput
*/
topic?: string | null;
/**
*
*
* @type {string}
* @memberof PublicMessageInput
*/
message?: string | null;
}

View File

@ -140,6 +140,14 @@ export interface SysFile {
*/ */
suffix?: string | null; suffix?: string | null;
/**
* MIME类型
*
* @type {string}
* @memberof SysFile
*/
contentType?: string | null;
/** /**
* *
* *