mirror of
https://gitee.com/RRQM_Home/TouchSocket.git
synced 2025-12-06 08:28:52 +08:00
发布:4.0.1
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
<Project>
|
||||
|
||||
<PropertyGroup>
|
||||
<BaseVersion>4.0.0</BaseVersion>
|
||||
<BaseVersion>4.0.1</BaseVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Release'">
|
||||
|
||||
@@ -15,17 +15,18 @@ using TouchSocket.Core.AspNetCore;
|
||||
|
||||
namespace TouchSocket.Core;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// AspNetCoreConfigExtension
|
||||
/// 提供AspNetCore容器扩展方法。
|
||||
/// </summary>
|
||||
public static class AspNetCoreConfigExtension
|
||||
{
|
||||
/// <summary>
|
||||
/// 使用<see cref="AspNetCoreContainer"/>作为容器。
|
||||
/// </summary>
|
||||
/// <param name="config"></param>
|
||||
/// <param name="services"></param>
|
||||
/// <returns></returns>
|
||||
/// <param name="config">配置对象</param>
|
||||
/// <param name="services">服务集合</param>
|
||||
/// <returns>配置对象</returns>
|
||||
public static TouchSocketConfig UseAspNetCoreContainer(this TouchSocketConfig config, IServiceCollection services)
|
||||
{
|
||||
config.SetRegistrator(new AspNetCoreContainer(services));
|
||||
@@ -35,13 +36,102 @@ public static class AspNetCoreConfigExtension
|
||||
/// <summary>
|
||||
/// 配置容器。
|
||||
/// </summary>
|
||||
/// <param name="services"></param>
|
||||
/// <param name="action"></param>
|
||||
/// <returns></returns>
|
||||
/// <param name="services">服务集合</param>
|
||||
/// <param name="action">配置操作</param>
|
||||
/// <returns>服务集合</returns>
|
||||
public static IServiceCollection ConfigureContainer(this IServiceCollection services, Action<IRegistrator> action)
|
||||
{
|
||||
var container = new AspNetCoreContainer(services);
|
||||
action.Invoke(container);
|
||||
return services;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置解析器。
|
||||
/// </summary>
|
||||
/// <param name="config">配置对象</param>
|
||||
/// <param name="provider">服务提供者</param>
|
||||
public static void SetResolver(this TouchSocketConfig config, IServiceProvider provider)
|
||||
{
|
||||
config.SetValue(TouchSocketCoreConfigExtension.ResolverProperty, new InternalResolver(provider));
|
||||
}
|
||||
|
||||
#region InternalResolver
|
||||
|
||||
/// <summary>
|
||||
/// 内部解析器。
|
||||
/// </summary>
|
||||
internal class InternalResolver : IResolver
|
||||
{
|
||||
private readonly IServiceProvider m_serviceProvider;
|
||||
private readonly IKeyedServiceProvider m_keyedServiceProvider;
|
||||
|
||||
/// <summary>
|
||||
/// 初始化<see cref="InternalResolver"/>的新实例。
|
||||
/// </summary>
|
||||
/// <param name="serviceProvider">服务提供者</param>
|
||||
public InternalResolver(IServiceProvider serviceProvider)
|
||||
{
|
||||
this.m_serviceProvider = serviceProvider;
|
||||
this.m_keyedServiceProvider = serviceProvider as IKeyedServiceProvider;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IScopedResolver CreateScopedResolver()
|
||||
{
|
||||
return new InternalScopedResolver(this.m_serviceProvider.CreateScope());
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public object GetService(Type serviceType)
|
||||
{
|
||||
return this.m_serviceProvider.GetService(serviceType);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public object Resolve(Type fromType, object key)
|
||||
{
|
||||
return this.m_keyedServiceProvider.GetKeyedService(fromType, key);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public object Resolve(Type fromType)
|
||||
{
|
||||
return this.m_serviceProvider.GetService(fromType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 内部作用域解析器。
|
||||
/// </summary>
|
||||
private class InternalScopedResolver : DisposableObject, IScopedResolver
|
||||
{
|
||||
private readonly IServiceScope serviceScope;
|
||||
private readonly InternalResolver resolver;
|
||||
|
||||
/// <summary>
|
||||
/// 初始化<see cref="InternalScopedResolver"/>的新实例。
|
||||
/// </summary>
|
||||
/// <param name="serviceScope">服务作用域</param>
|
||||
public InternalScopedResolver(IServiceScope serviceScope)
|
||||
{
|
||||
this.serviceScope = serviceScope;
|
||||
this.resolver = new InternalResolver(serviceScope.ServiceProvider);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IResolver Resolver => this.resolver;
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
this.serviceScope.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -45,6 +45,7 @@ public sealed class ByteBlock : IByteBlock
|
||||
public ByteBlock(Memory<byte> memory)
|
||||
{
|
||||
this.m_memory = memory;
|
||||
this.m_length = memory.Length;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -44,6 +44,7 @@ public struct ValueByteBlock : IByteBlock
|
||||
public ValueByteBlock(Memory<byte> memory)
|
||||
{
|
||||
this.m_memory = memory;
|
||||
this.m_length = memory.Length;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -26,7 +26,7 @@ public interface IBytesBuilder
|
||||
int MaxLength { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 构建对象到<see cref="ByteBlock"/>
|
||||
/// 构建对象到<see cref="IBytesWriter"/>
|
||||
/// </summary>
|
||||
/// <param name="writer">要构建的字节块对象引用。</param>
|
||||
void Build<TWriter>(ref TWriter writer) where TWriter : IBytesWriter
|
||||
|
||||
@@ -16,8 +16,10 @@ using System.IO.Pipelines;
|
||||
namespace TouchSocket.Core;
|
||||
|
||||
/// <summary>
|
||||
///单线程状况的流式数据处理适配器测试
|
||||
/// 单线程状况的流式数据处理适配器测试。
|
||||
/// </summary>
|
||||
/// <typeparam name="TAdapter">自定义数据处理适配器类型。</typeparam>
|
||||
/// <typeparam name="TRequest">请求信息类型。</typeparam>
|
||||
public class SingleStreamDataAdapterTester<TAdapter, TRequest>
|
||||
where TAdapter : CustomDataHandlingAdapter<TRequest>
|
||||
where TRequest : class, IRequestInfo
|
||||
@@ -32,12 +34,23 @@ public class SingleStreamDataAdapterTester<TAdapter, TRequest>
|
||||
/// <summary>
|
||||
/// Tcp数据处理适配器测试
|
||||
/// </summary>
|
||||
/// <param name="adapter">自定义数据处理适配器实例。</param>
|
||||
/// <param name="receivedCallBack">接收回调委托。</param>
|
||||
public SingleStreamDataAdapterTester(TAdapter adapter, Action<TRequest> receivedCallBack = default)
|
||||
{
|
||||
this.m_adapter = adapter;
|
||||
this.m_receivedCallBack = receivedCallBack;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步运行测试。
|
||||
/// </summary>
|
||||
/// <param name="memory">要发送的数据内存块。</param>
|
||||
/// <param name="testCount">测试发送次数。</param>
|
||||
/// <param name="expectedCount">预期接收次数。</param>
|
||||
/// <param name="bufferLength">每次写入的缓冲区长度。</param>
|
||||
/// <param name="cancellationToken">取消操作的令牌。</param>
|
||||
/// <returns>返回测试所用的时间。</returns>
|
||||
public async Task<TimeSpan> RunAsync(ReadOnlyMemory<byte> memory, int testCount, int expectedCount, int bufferLength, CancellationToken cancellationToken)
|
||||
{
|
||||
this.m_count = 0;
|
||||
|
||||
@@ -13,10 +13,14 @@
|
||||
namespace TouchSocket.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Udp数据处理适配器测试
|
||||
/// Udp数据处理适配器测试。
|
||||
/// </summary>
|
||||
public class UdpDataAdapterTester : MultithreadingDataAdapterTester
|
||||
{
|
||||
/// <summary>
|
||||
/// 初始化 <see cref="UdpDataAdapterTester"/> 类的新实例。
|
||||
/// </summary>
|
||||
/// <param name="multiThread">多线程数量。</param>
|
||||
protected UdpDataAdapterTester(int multiThread) : base(multiThread)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ using System.Net;
|
||||
namespace TouchSocket.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Udp数据处理适配器
|
||||
/// Udp数据处理适配器。
|
||||
/// </summary>
|
||||
public abstract class UdpDataHandlingAdapter : DataHandlingAdapter
|
||||
{
|
||||
@@ -23,38 +23,32 @@ public abstract class UdpDataHandlingAdapter : DataHandlingAdapter
|
||||
public override bool CanSendRequestInfo => false;
|
||||
|
||||
/// <summary>
|
||||
/// 当接收数据处理完成后,回调该函数执行接收
|
||||
/// 当接收数据处理完成后,回调该函数执行接收。
|
||||
/// </summary>
|
||||
public Func<EndPoint, ReadOnlyMemory<byte>, IRequestInfo, Task> ReceivedCallBack { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 当接收数据处理完成后,异步回调该函数执行发送
|
||||
/// 当接收数据处理完成后,异步回调该函数执行发送。
|
||||
/// </summary>
|
||||
public Func<EndPoint, ReadOnlyMemory<byte>, CancellationToken, Task> SendCallBackAsync { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 收到数据的切入点,该方法由框架自动调用。
|
||||
/// </summary>
|
||||
/// <param name="remoteEndPoint"></param>
|
||||
/// <param name="memory"></param>
|
||||
/// <param name="remoteEndPoint">远程端点。</param>
|
||||
/// <param name="memory">接收到的数据。</param>
|
||||
public Task ReceivedInputAsync(EndPoint remoteEndPoint, ReadOnlyMemory<byte> memory)
|
||||
{
|
||||
return this.PreviewReceivedAsync(remoteEndPoint, memory);
|
||||
}
|
||||
|
||||
#region SendInputAsync
|
||||
|
||||
/// <summary>
|
||||
/// 异步发送输入数据。
|
||||
/// </summary>
|
||||
/// <param name="endPoint">要发送数据的端点。</param>
|
||||
/// <param name="memory">包含要发送的数据的只读内存。</param>
|
||||
/// <param name="cancellationToken">可取消令箭</param>
|
||||
/// <param name="cancellationToken">可取消令箭。</param>
|
||||
/// <returns>返回一个任务,表示发送操作。</returns>
|
||||
/// <remarks>
|
||||
/// 此方法是一个异步操作,用于向指定的端点发送输入数据。
|
||||
/// 它使用PreviewSendAsync方法来执行实际的发送操作。
|
||||
/// </remarks>
|
||||
public Task SendInputAsync(EndPoint endPoint, ReadOnlyMemory<byte> memory, CancellationToken cancellationToken)
|
||||
{
|
||||
return this.PreviewSendAsync(endPoint, memory, cancellationToken);
|
||||
@@ -63,22 +57,21 @@ public abstract class UdpDataHandlingAdapter : DataHandlingAdapter
|
||||
/// <summary>
|
||||
/// 发送数据的切入点,该方法由框架自动调用。
|
||||
/// </summary>
|
||||
/// <param name="endPoint"></param>
|
||||
/// <param name="requestInfo"></param>
|
||||
/// <param name="cancellationToken">可取消令箭</param>
|
||||
/// <param name="endPoint">目标端点。</param>
|
||||
/// <param name="requestInfo">请求信息。</param>
|
||||
/// <param name="cancellationToken">可取消令箭。</param>
|
||||
public Task SendInputAsync(EndPoint endPoint, IRequestInfo requestInfo, CancellationToken cancellationToken)
|
||||
{
|
||||
return this.PreviewSendAsync(endPoint, requestInfo, cancellationToken);
|
||||
}
|
||||
#endregion SendInputAsync
|
||||
|
||||
/// <summary>
|
||||
/// 处理已经经过预先处理后的数据
|
||||
/// 处理已经经过预先处理后的数据。
|
||||
/// </summary>
|
||||
/// <param name="remoteEndPoint">远程端点,标识数据来源</param>
|
||||
/// <param name="memory">接收到的二进制数据块</param>
|
||||
/// <param name="requestInfo">解析后的请求信息</param>
|
||||
/// <returns>一个异步任务,代表处理过程</returns>
|
||||
/// <param name="remoteEndPoint">远程端点,标识数据来源。</param>
|
||||
/// <param name="memory">接收到的二进制数据块。</param>
|
||||
/// <param name="requestInfo">解析后的请求信息。</param>
|
||||
/// <returns>一个异步任务,代表处理过程。</returns>
|
||||
protected Task GoReceived(EndPoint remoteEndPoint, ReadOnlyMemory<byte> memory, IRequestInfo requestInfo)
|
||||
{
|
||||
// 调用接收回调,继续处理接收到的数据
|
||||
@@ -86,32 +79,33 @@ public abstract class UdpDataHandlingAdapter : DataHandlingAdapter
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送已经经过预先处理后的数据
|
||||
/// 发送已经经过预先处理后的数据。
|
||||
/// </summary>
|
||||
/// <param name="endPoint">目标端点,表示数据发送的目的地址</param>
|
||||
/// <param name="memory">已经经过预先处理的字节数据,以 ReadOnlyMemory 方式传递以提高性能</param>
|
||||
/// <param name="cancellationToken">可取消令箭</param>
|
||||
/// <returns>返回一个 Task 对象,表示异步操作的完成</returns>
|
||||
/// <param name="endPoint">目标端点,表示数据发送的目的地址。</param>
|
||||
/// <param name="memory">已经经过预先处理的字节数据。</param>
|
||||
/// <param name="cancellationToken">可取消令箭。</param>
|
||||
/// <returns>返回一个任务,表示异步操作的完成。</returns>
|
||||
protected Task GoSendAsync(EndPoint endPoint, ReadOnlyMemory<byte> memory, CancellationToken cancellationToken)
|
||||
{
|
||||
return this.SendCallBackAsync.Invoke(endPoint, memory, cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当接收到数据后预先处理数据,然后调用<see cref="GoReceived(EndPoint,IByteBlockReader, IRequestInfo)"/>处理数据
|
||||
/// 在接收数据前预先处理数据。
|
||||
/// </summary>
|
||||
/// <param name="remoteEndPoint"></param>
|
||||
/// <param name="memory"></param>
|
||||
/// <param name="remoteEndPoint">远程端点。</param>
|
||||
/// <param name="memory">接收到的数据。</param>
|
||||
protected virtual async Task PreviewReceivedAsync(EndPoint remoteEndPoint, ReadOnlyMemory<byte> memory)
|
||||
{
|
||||
await this.GoReceived(remoteEndPoint, memory, default).ConfigureAwait(EasyTask.ContinueOnCapturedContext);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当发送数据前预先处理数据
|
||||
/// 当发送数据前预先处理数据。
|
||||
/// </summary>
|
||||
/// <param name="endPoint"></param>
|
||||
/// <param name="requestInfo"></param>
|
||||
/// <param name="cancellationToken">可取消令箭</param>
|
||||
/// <param name="endPoint">目标端点。</param>
|
||||
/// <param name="requestInfo">请求信息。</param>
|
||||
/// <param name="cancellationToken">可取消令箭。</param>
|
||||
protected virtual async Task PreviewSendAsync(EndPoint endPoint, IRequestInfo requestInfo, CancellationToken cancellationToken)
|
||||
{
|
||||
ThrowHelper.ThrowIfNull(requestInfo, nameof(requestInfo));
|
||||
@@ -135,8 +129,8 @@ public abstract class UdpDataHandlingAdapter : DataHandlingAdapter
|
||||
/// </summary>
|
||||
/// <param name="endPoint">数据发送的目标端点。</param>
|
||||
/// <param name="memory">待发送的字节数据内存。</param>
|
||||
/// <param name="cancellationToken">可取消令箭</param>
|
||||
/// <returns>一个表示异步操作完成的 <see cref="Task"/> 对象。</returns>
|
||||
/// <param name="cancellationToken">可取消令箭。</param>
|
||||
/// <returns>一个表示异步操作完成的任务。</returns>
|
||||
protected virtual Task PreviewSendAsync(EndPoint endPoint, ReadOnlyMemory<byte> memory, CancellationToken cancellationToken)
|
||||
{
|
||||
return this.GoSendAsync(endPoint, memory, cancellationToken);
|
||||
@@ -145,12 +139,10 @@ public abstract class UdpDataHandlingAdapter : DataHandlingAdapter
|
||||
/// <inheritdoc/>
|
||||
protected override void Reset()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void SafetyDispose(bool disposing)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,7 @@ using System.Runtime.InteropServices;
|
||||
namespace TouchSocket.Core;
|
||||
|
||||
/// <summary>
|
||||
/// 为System提供扩展。
|
||||
/// 为 <see cref="System"/> 提供扩展方法。
|
||||
/// </summary>
|
||||
public static class SystemExtension
|
||||
{
|
||||
@@ -85,11 +85,11 @@ public static class SystemExtension
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取枚举成员上绑定的指定类型的自定义属性
|
||||
/// 获取枚举成员上绑定的指定类型的自定义属性。
|
||||
/// </summary>
|
||||
/// <param name="enumObj">枚举对象</param>
|
||||
/// <typeparam name="T">要获取的属性类型</typeparam>
|
||||
/// <returns>指定类型的自定义属性</returns>
|
||||
/// <typeparam name="T">要获取的属性类型。</typeparam>
|
||||
/// <param name="enumObj">枚举对象。</param>
|
||||
/// <returns>指定类型的自定义属性。</returns>
|
||||
public static T GetAttribute<T>(this Enum enumObj) where T : Attribute
|
||||
{
|
||||
// 获取枚举对象的类型
|
||||
@@ -110,13 +110,12 @@ public static class SystemExtension
|
||||
#region SetBit
|
||||
|
||||
/// <summary>
|
||||
/// 对于给定的无符号长整型数值,设置指定索引位置的位值为指定的布尔值。
|
||||
/// 设置无符号长整型数值的指定位。
|
||||
/// </summary>
|
||||
/// <param name="value">原始数值。</param>
|
||||
/// <param name="index">位索引,范围为0到63。</param>
|
||||
/// <param name="bitvalue">要设置的位值(true为1,false为0)。</param>
|
||||
/// <param name="index">位索引。</param>
|
||||
/// <param name="bitvalue">要设置的位值。</param>
|
||||
/// <returns>修改后的数值。</returns>
|
||||
/// <exception cref="ArgumentOutOfRangeException">当索引值不在有效范围内时抛出异常。</exception>
|
||||
public static ulong SetBit(this ulong value, int index, bool bitvalue)
|
||||
{
|
||||
var accessor = new BitAccessor<ulong>(ref value);
|
||||
@@ -173,7 +172,7 @@ public static class SystemExtension
|
||||
|
||||
#region GetBit
|
||||
/// <summary>
|
||||
/// 获取无符号长整型数值中的指定位置的位是否为1。
|
||||
/// 获取无符号长整型数值的指定位。
|
||||
/// </summary>
|
||||
/// <param name="value">要检查的无符号长整型数值。</param>
|
||||
/// <param name="index">要检查的位的位置,从0到63。</param>
|
||||
@@ -228,13 +227,26 @@ public static class SystemExtension
|
||||
#region Byte[]
|
||||
|
||||
/// <summary>
|
||||
/// 字节数组转16进制字符
|
||||
/// 将字节数组转换为十六进制字符串。
|
||||
/// </summary>
|
||||
/// <param name="buffer"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <param name="length"></param>
|
||||
/// <param name="split"></param>
|
||||
/// <returns></returns>
|
||||
/// <param name="buffer">字节数组。</param>
|
||||
/// <param name="split">分隔符。</param>
|
||||
/// <returns>十六进制字符串。</returns>
|
||||
public static string ByBytesToHexString(this byte[] buffer, string split = default)
|
||||
{
|
||||
return string.IsNullOrEmpty(split)
|
||||
? BitConverter.ToString(buffer).Replace("-", string.Empty)
|
||||
: BitConverter.ToString(buffer).Replace("-", split);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将字节缓冲区转换为十六进制字符串。
|
||||
/// </summary>
|
||||
/// <param name="buffer">要转换的字节缓冲区。</param>
|
||||
/// <param name="offset">缓冲区的起始索引。</param>
|
||||
/// <param name="length">要转换的字节数。</param>
|
||||
/// <param name="split">可选参数,用于指定分隔符,默认为空。</param>
|
||||
/// <returns>转换后的十六进制字符串。</returns>
|
||||
public static string ByBytesToHexString(this byte[] buffer, int offset, int length, string split = default)
|
||||
{
|
||||
return string.IsNullOrEmpty(split)
|
||||
@@ -242,17 +254,6 @@ public static class SystemExtension
|
||||
: BitConverter.ToString(buffer, offset, length).Replace("-", split);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 将字节缓冲区转换为十六进制字符串。
|
||||
/// </summary>
|
||||
/// <param name="buffer">要转换的字节缓冲区。</param>
|
||||
/// <param name="split">可选参数,用于指定分隔符,默认为空。</param>
|
||||
/// <returns>转换后的十六进制字符串。</returns>
|
||||
public static string ByBytesToHexString(this byte[] buffer, string split = default)
|
||||
{
|
||||
return ByBytesToHexString(buffer, 0, buffer.Length, split);
|
||||
}
|
||||
/// <summary>
|
||||
/// 索引第一个包含数组的索引位置,例如:在{0,1,2,3,1,2,3}中索引{2,3},则返回3。
|
||||
/// <para>如果目标数组为<see langword="null"/>或长度为0,则直接返回offset的值</para>
|
||||
@@ -1000,6 +1001,12 @@ public static class SystemExtension
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步读取流中的所有字节。
|
||||
/// </summary>
|
||||
/// <param name="stream">流。</param>
|
||||
/// <param name="cancellationToken">取消令牌。</param>
|
||||
/// <returns>字节数组。</returns>
|
||||
public static async Task<byte[]> ReadAllToByteArrayAsync(this Stream stream, CancellationToken cancellationToken)
|
||||
{
|
||||
using (var memoryStream = new MemoryStream())
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
namespace TouchSocket.Core;
|
||||
|
||||
/// <summary>
|
||||
/// 简化版文件存储器
|
||||
/// 简化版文件存储器。
|
||||
/// </summary>
|
||||
public sealed partial class FileStorage : IDisposable
|
||||
{
|
||||
@@ -21,6 +21,10 @@ public sealed partial class FileStorage : IDisposable
|
||||
internal int m_referenceCount;
|
||||
private bool m_disposed;
|
||||
|
||||
/// <summary>
|
||||
/// 初始化 <see cref="FileStorage"/> 类的新实例。
|
||||
/// </summary>
|
||||
/// <param name="path">文件路径。</param>
|
||||
internal FileStorage(string path)
|
||||
{
|
||||
this.Path = path;
|
||||
@@ -28,12 +32,12 @@ public sealed partial class FileStorage : IDisposable
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 文件路径
|
||||
/// 获取文件路径。
|
||||
/// </summary>
|
||||
public string Path { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 文件长度
|
||||
/// 获取文件长度。
|
||||
/// </summary>
|
||||
public long Length
|
||||
{
|
||||
@@ -52,14 +56,25 @@ public sealed partial class FileStorage : IDisposable
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取一个值,指示是否可以读取文件。
|
||||
/// </summary>
|
||||
public bool CanRead => this.m_fileStream.CanRead;
|
||||
|
||||
/// <summary>
|
||||
/// 获取一个值,指示是否可以查找文件位置。
|
||||
/// </summary>
|
||||
public bool CanSeek => this.m_fileStream.CanSeek;
|
||||
|
||||
/// <summary>
|
||||
/// 获取一个值,指示是否可以写入文件。
|
||||
/// </summary>
|
||||
public bool CanWrite => this.m_fileStream.CanWrite;
|
||||
|
||||
/// <summary>
|
||||
/// 设置文件长度
|
||||
/// 设置文件长度。
|
||||
/// </summary>
|
||||
/// <param name="length">新长度</param>
|
||||
/// <param name="length">新长度。</param>
|
||||
public void SetLength(long length)
|
||||
{
|
||||
this.m_semaphore.Wait();
|
||||
@@ -75,7 +90,7 @@ public sealed partial class FileStorage : IDisposable
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 刷新缓冲区
|
||||
/// 刷新缓冲区。
|
||||
/// </summary>
|
||||
public void Flush()
|
||||
{
|
||||
@@ -142,13 +157,13 @@ public sealed partial class FileStorage : IDisposable
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取数据
|
||||
/// 读取数据。
|
||||
/// </summary>
|
||||
/// <param name="position">读取位置</param>
|
||||
/// <param name="buffer">缓冲区</param>
|
||||
/// <param name="offset">缓冲区偏移量</param>
|
||||
/// <param name="count">读取字节数</param>
|
||||
/// <returns>实际读取的字节数</returns>
|
||||
/// <param name="position">读取位置。</param>
|
||||
/// <param name="buffer">缓冲区。</param>
|
||||
/// <param name="offset">缓冲区偏移量。</param>
|
||||
/// <param name="count">读取字节数。</param>
|
||||
/// <returns>实际读取的字节数。</returns>
|
||||
public int Read(long position, byte[] buffer, int offset, int count)
|
||||
{
|
||||
this.m_semaphore.Wait();
|
||||
@@ -165,12 +180,12 @@ public sealed partial class FileStorage : IDisposable
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 写入数据
|
||||
/// 写入数据。
|
||||
/// </summary>
|
||||
/// <param name="position">写入位置</param>
|
||||
/// <param name="buffer">数据</param>
|
||||
/// <param name="offset">缓冲区偏移量</param>
|
||||
/// <param name="count">写入字节数</param>
|
||||
/// <param name="position">写入位置。</param>
|
||||
/// <param name="buffer">数据。</param>
|
||||
/// <param name="offset">缓冲区偏移量。</param>
|
||||
/// <param name="count">写入字节数。</param>
|
||||
public void Write(long position, byte[] buffer, int offset, int count)
|
||||
{
|
||||
this.m_semaphore.Wait();
|
||||
@@ -187,12 +202,12 @@ public sealed partial class FileStorage : IDisposable
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步读取数据
|
||||
/// 异步读取数据。
|
||||
/// </summary>
|
||||
/// <param name="position">读取位置</param>
|
||||
/// <param name="memory">缓冲区</param>
|
||||
/// <param name="cancellationToken">取消令牌</param>
|
||||
/// <returns>实际读取的字节数</returns>
|
||||
/// <param name="position">读取位置。</param>
|
||||
/// <param name="memory">缓冲区。</param>
|
||||
/// <param name="cancellationToken">取消令牌。</param>
|
||||
/// <returns>实际读取的字节数。</returns>
|
||||
public async Task<int> ReadAsync(long position, Memory<byte> memory, CancellationToken cancellationToken = default)
|
||||
{
|
||||
await this.m_semaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
|
||||
@@ -209,11 +224,11 @@ public sealed partial class FileStorage : IDisposable
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步写入数据
|
||||
/// 异步写入数据。
|
||||
/// </summary>
|
||||
/// <param name="position">写入位置</param>
|
||||
/// <param name="memory">数据</param>
|
||||
/// <param name="cancellationToken">取消令牌</param>
|
||||
/// <param name="position">写入位置。</param>
|
||||
/// <param name="memory">数据。</param>
|
||||
/// <param name="cancellationToken">取消令牌。</param>
|
||||
public async Task WriteAsync(long position, ReadOnlyMemory<byte> memory, CancellationToken cancellationToken = default)
|
||||
{
|
||||
await this.m_semaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
|
||||
@@ -230,9 +245,9 @@ public sealed partial class FileStorage : IDisposable
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步刷新缓冲区
|
||||
/// 异步刷新缓冲区。
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">取消令牌</param>
|
||||
/// <param name="cancellationToken">取消令牌。</param>
|
||||
public async Task FlushAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
await this.m_semaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
|
||||
@@ -247,13 +262,12 @@ public sealed partial class FileStorage : IDisposable
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 读取数据
|
||||
/// 读取数据。
|
||||
/// </summary>
|
||||
/// <param name="position">读取位置</param>
|
||||
/// <param name="buffer">缓冲区</param>
|
||||
/// <returns>实际读取的字节数</returns>
|
||||
/// <param name="position">读取位置。</param>
|
||||
/// <param name="buffer">缓冲区。</param>
|
||||
/// <returns>实际读取的字节数。</returns>
|
||||
public int Read(long position, Span<byte> buffer)
|
||||
{
|
||||
this.m_semaphore.Wait();
|
||||
@@ -270,10 +284,10 @@ public sealed partial class FileStorage : IDisposable
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 写入数据
|
||||
/// 写入数据。
|
||||
/// </summary>
|
||||
/// <param name="position">写入位置</param>
|
||||
/// <param name="buffer">数据</param>
|
||||
/// <param name="position">写入位置。</param>
|
||||
/// <param name="buffer">数据。</param>
|
||||
public void Write(long position, ReadOnlySpan<byte> buffer)
|
||||
{
|
||||
this.m_semaphore.Wait();
|
||||
|
||||
@@ -15,6 +15,9 @@ using System.Reflection;
|
||||
|
||||
namespace TouchSocket.Core;
|
||||
|
||||
/// <summary>
|
||||
/// 表示一个字段的封装。
|
||||
/// </summary>
|
||||
public sealed class Field
|
||||
{
|
||||
/// <summary>
|
||||
@@ -30,7 +33,7 @@ public sealed class Field
|
||||
/// <summary>
|
||||
/// 字段
|
||||
/// </summary>
|
||||
/// <param name="fieldInfo">字段信息</param>
|
||||
/// <param name="fieldInfo">字段信息。</param>
|
||||
public Field(FieldInfo fieldInfo)
|
||||
{
|
||||
this.Info = fieldInfo;
|
||||
@@ -44,37 +47,37 @@ public sealed class Field
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取字段信息
|
||||
/// 获取字段信息。
|
||||
/// </summary>
|
||||
public FieldInfo Info { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 从类型的字段获取字段
|
||||
/// 从类型的字段获取字段。
|
||||
/// </summary>
|
||||
/// <param name="type">类型</param>
|
||||
/// <returns></returns>
|
||||
/// <param name="type">类型。</param>
|
||||
/// <returns>字段数组。</returns>
|
||||
public static Field[] GetFields([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)] Type type)
|
||||
{
|
||||
return type.GetFields().Select(p => new Field(p)).ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取字段的值
|
||||
/// 获取字段的值。
|
||||
/// </summary>
|
||||
/// <param name="instance">实例</param>
|
||||
/// <exception cref="NotSupportedException"></exception>
|
||||
/// <returns></returns>
|
||||
/// <param name="instance">实例。</param>
|
||||
/// <returns>字段的值。</returns>
|
||||
/// <exception cref="NotSupportedException">当字段不支持获取值时抛出。</exception>
|
||||
public object GetValue(object instance)
|
||||
{
|
||||
return this.m_geter == null ? throw new NotSupportedException() : this.m_geter.Invoke(instance);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置字段的值
|
||||
/// 设置字段的值。
|
||||
/// </summary>
|
||||
/// <param name="instance">实例</param>
|
||||
/// <param name="value">值</param>
|
||||
/// <exception cref="NotSupportedException"></exception>
|
||||
/// <param name="instance">实例。</param>
|
||||
/// <param name="value">值。</param>
|
||||
/// <exception cref="NotSupportedException">当字段不支持设置值时抛出。</exception>
|
||||
public void SetValue(object instance, object value)
|
||||
{
|
||||
if (this.m_seter == null)
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System.Buffers;
|
||||
using System.Collections;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.CompilerServices;
|
||||
@@ -133,11 +134,11 @@ public static class FastBinaryFormatter
|
||||
[RequiresUnreferencedCode("此方法可能会使用反射构建访问器,与剪裁不兼容。如果已使用源生成上下文,可以忽略此警告。")]
|
||||
public static byte[] SerializeToBytes<[DynamicallyAccessedMembers(AOT.FastBinaryFormatter)] T>(in T graph, FastSerializerContext serializerContext = null)
|
||||
{
|
||||
var byteBlock = new ValueByteBlock(1024 * 64);
|
||||
var byteBlock = new SegmentedBytesWriter();
|
||||
try
|
||||
{
|
||||
Serialize(ref byteBlock, graph, serializerContext);
|
||||
return byteBlock.ToArray();
|
||||
return byteBlock.Sequence.ToArray();
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -339,8 +340,8 @@ public static class FastBinaryFormatter
|
||||
[RequiresUnreferencedCode("此方法可能会使用反射构建访问器,与剪裁不兼容。如果已使用源生成上下文,可以忽略此警告。")]
|
||||
public static T Deserialize<[DynamicallyAccessedMembers(AOT.FastBinaryFormatter)] T>(byte[] bytes, FastSerializerContext serializerContext = null)
|
||||
{
|
||||
var byteBlock = new ValueByteBlock(bytes);
|
||||
return Deserialize<ValueByteBlock, T>(ref byteBlock, serializerContext);
|
||||
var reader = new BytesReader(bytes);
|
||||
return Deserialize<BytesReader, T>(ref reader, serializerContext);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -406,11 +407,9 @@ public static class FastBinaryFormatter
|
||||
// 复杂类型:先读体长度
|
||||
var len = ReaderExtension.ReadValue<TReader, int>(ref reader);
|
||||
var serializeObj = serializerContext.GetSerializeObject(type);
|
||||
if (serializeObj.Converter != null)
|
||||
{
|
||||
return serializeObj.Converter.Read(ref reader, type);
|
||||
}
|
||||
return DeserializeClass(type, serializeObj, ref reader, len, serializerContext);
|
||||
return serializeObj.Converter != null
|
||||
? serializeObj.Converter.Read(ref reader, type)
|
||||
: DeserializeClass(type, serializeObj, ref reader, len, serializerContext);
|
||||
}
|
||||
|
||||
[UnconditionalSuppressMessage("AOT", "IL3050", Justification = "数组元素类型已通过DynamicallyAccessedMembers标记保证存在")]
|
||||
|
||||
@@ -19,6 +19,7 @@ namespace TouchSocket.Core;
|
||||
/// </summary>
|
||||
/// <typeparam name="TState"></typeparam>
|
||||
[RequiresUnreferencedCode("Members from deserialized types may be trimmed if not referenced directly")]
|
||||
[RequiresDynamicCode("XML serializer relies on dynamic code generation which is not available with Ahead of Time compilation")]
|
||||
public class XmlStringToClassSerializerFormatter<TState> : ISerializerFormatter<string, TState>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
|
||||
@@ -36,30 +36,25 @@ public sealed class WebSocketFeatureOptions
|
||||
/// 设置是否自动处理Close报文
|
||||
/// </summary>
|
||||
/// <param name="autoClose">是否自动处理Close报文</param>
|
||||
/// <returns>返回当前配置选项实例,支持链式调用</returns>
|
||||
public WebSocketFeatureOptions SetAutoClose(bool autoClose)
|
||||
public void SetAutoClose(bool autoClose)
|
||||
{
|
||||
this.AutoClose = autoClose;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置是否自动回应Ping报文
|
||||
/// </summary>
|
||||
/// <param name="autoPong">是否自动回应Ping报文</param>
|
||||
/// <returns>返回当前配置选项实例,支持链式调用</returns>
|
||||
public WebSocketFeatureOptions SetAutoPong(bool autoPong)
|
||||
public void SetAutoPong(bool autoPong)
|
||||
{
|
||||
this.AutoPong = autoPong;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置WebSocket连接的URL路径
|
||||
/// </summary>
|
||||
/// <param name="url">WebSocket连接路径,如果为null或空则表示所有连接都解释为WS</param>
|
||||
/// <returns>返回当前配置选项实例,支持链式调用</returns>
|
||||
public WebSocketFeatureOptions SetUrl(string url = "/ws")
|
||||
public void SetUrl(string url = "/ws")
|
||||
{
|
||||
if (url.IsNullOrEmpty())
|
||||
{
|
||||
@@ -72,22 +67,15 @@ public sealed class WebSocketFeatureOptions
|
||||
|
||||
this.SetVerifyConnection((client, context) =>
|
||||
{
|
||||
if (url == "/" || context.Request.UrlEquals(url))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return url == "/" || context.Request.UrlEquals(url);
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置验证连接的同步方法
|
||||
/// </summary>
|
||||
/// <param name="verifyConnection">验证连接的同步委托</param>
|
||||
/// <returns>返回当前配置选项实例,支持链式调用</returns>
|
||||
public WebSocketFeatureOptions SetVerifyConnection(Func<IHttpSessionClient, HttpContext, bool> verifyConnection)
|
||||
public void SetVerifyConnection(Func<IHttpSessionClient, HttpContext, bool> verifyConnection)
|
||||
{
|
||||
ThrowHelper.ThrowIfNull(verifyConnection, nameof(verifyConnection));
|
||||
|
||||
@@ -96,18 +84,15 @@ public sealed class WebSocketFeatureOptions
|
||||
await EasyTask.CompletedTask.ConfigureAwait(EasyTask.ContinueOnCapturedContext);
|
||||
return verifyConnection.Invoke(client, context);
|
||||
};
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置验证连接的异步方法
|
||||
/// </summary>
|
||||
/// <param name="verifyConnection">验证连接的异步委托</param>
|
||||
/// <returns>返回当前配置选项实例,支持链式调用</returns>
|
||||
public WebSocketFeatureOptions SetVerifyConnection(Func<IHttpSessionClient, HttpContext, Task<bool>> verifyConnection)
|
||||
public void SetVerifyConnection(Func<IHttpSessionClient, HttpContext, Task<bool>> verifyConnection)
|
||||
{
|
||||
ThrowHelper.ThrowIfNull(verifyConnection, nameof(verifyConnection));
|
||||
this.VerifyConnection = verifyConnection;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,7 @@ using TouchSocket.Sockets;
|
||||
|
||||
namespace TouchSocket.Mqtt;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public abstract class MqttActor : DisposableObject, IOnlineClient
|
||||
{
|
||||
#region 字段
|
||||
@@ -24,11 +25,7 @@ public abstract class MqttActor : DisposableObject, IOnlineClient
|
||||
|
||||
#endregion 字段
|
||||
|
||||
public MqttActor()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (this.DisposedValue)
|
||||
@@ -44,6 +41,7 @@ public abstract class MqttActor : DisposableObject, IOnlineClient
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected virtual Task PublishMessageArrivedAsync(MqttArrivedMessage message)
|
||||
{
|
||||
if (this.MessageArrived != null)
|
||||
@@ -59,18 +57,23 @@ public abstract class MqttActor : DisposableObject, IOnlineClient
|
||||
|
||||
#region 属性
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string Id { get; protected set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool Online { get; protected set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public CancellationTokenSource TokenSource => this.m_tokenSource;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public WaitHandlePool<MqttIdentifierMessage> WaitHandlePool => this.m_waitHandlePool;
|
||||
|
||||
#endregion 属性
|
||||
|
||||
#region Publish
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Task PublishAsync(MqttPublishMessage message, CancellationToken cancellationToken)
|
||||
{
|
||||
switch (message.QosLevel)
|
||||
@@ -137,6 +140,7 @@ public abstract class MqttActor : DisposableObject, IOnlineClient
|
||||
|
||||
#region InputMqttMessage
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task InputMqttMessageAsync(MqttMessage mqttMessage, CancellationToken cancellationToken)
|
||||
{
|
||||
switch (mqttMessage)
|
||||
@@ -385,17 +389,24 @@ public abstract class MqttActor : DisposableObject, IOnlineClient
|
||||
|
||||
#region 委托
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Func<MqttActor, MqttClosingEventArgs, Task> Closing { get; set; }
|
||||
/// <inheritdoc/>
|
||||
public Func<MqttActor, MqttConnectedEventArgs, Task> Connected { get; set; }
|
||||
/// <inheritdoc/>
|
||||
public Func<MqttActor, MqttConnectingEventArgs, Task> Connecting { get; set; }
|
||||
/// <inheritdoc/>
|
||||
public Func<MqttActor, MqttReceivedEventArgs, Task> MessageArrived { get; set; }
|
||||
/// <inheritdoc/>
|
||||
public Func<MqttActor, MqttMessage, CancellationToken, Task> OutputSendAsync { get; set; }
|
||||
/// <inheritdoc/>
|
||||
public MqttProtocolVersion Version { get; protected set; }
|
||||
|
||||
#endregion 委托
|
||||
|
||||
#region 委托方法
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected async Task ProtectedMqttOnClosing(MqttDisconnectMessage message)
|
||||
{
|
||||
if (this.Closing != null)
|
||||
@@ -404,6 +415,7 @@ public abstract class MqttActor : DisposableObject, IOnlineClient
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected async Task ProtectedMqttOnConnected(MqttConnectedEventArgs e)
|
||||
{
|
||||
if (this.Connected != null)
|
||||
@@ -412,6 +424,7 @@ public abstract class MqttActor : DisposableObject, IOnlineClient
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected async Task ProtectedMqttOnConnecting(MqttConnectingEventArgs e)
|
||||
{
|
||||
if (this.Connecting != null)
|
||||
@@ -420,6 +433,7 @@ public abstract class MqttActor : DisposableObject, IOnlineClient
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected Task ProtectedOutputSendAsync(MqttMessage message, CancellationToken cancellationToken)
|
||||
{
|
||||
if (message.MessageType == MqttMessageType.Connect)
|
||||
|
||||
@@ -17,6 +17,11 @@ public sealed class MqttClientActor : MqttActor
|
||||
private TaskCompletionSource<MqttConnAckMessage> m_waitForConnect;
|
||||
private readonly WaitDataAsync<MqttPingRespMessage> m_waitForPing = new();
|
||||
|
||||
/// <summary>
|
||||
/// 异步断开连接。
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">取消令牌。</param>
|
||||
/// <returns>任务。</returns>
|
||||
public async Task DisconnectAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
if (!this.Online)
|
||||
@@ -36,6 +41,11 @@ public sealed class MqttClientActor : MqttActor
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步发送PING消息。
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">取消令牌。</param>
|
||||
/// <returns>操作结果。</returns>
|
||||
public async ValueTask<Result> PingAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
var contentForAck = new MqttPingReqMessage();
|
||||
@@ -54,8 +64,12 @@ public sealed class MqttClientActor : MqttActor
|
||||
};
|
||||
}
|
||||
|
||||
#region 连接
|
||||
|
||||
/// <summary>
|
||||
/// 异步连接。
|
||||
/// </summary>
|
||||
/// <param name="message">连接消息。</param>
|
||||
/// <param name="cancellationToken">取消令牌。</param>
|
||||
/// <returns>连接确认消息。</returns>
|
||||
public async Task<MqttConnAckMessage> ConnectAsync(MqttConnectMessage message, CancellationToken cancellationToken)
|
||||
{
|
||||
this.m_waitForConnect = new TaskCompletionSource<MqttConnAckMessage>();
|
||||
@@ -66,32 +80,35 @@ public sealed class MqttClientActor : MqttActor
|
||||
return connAckMessage;
|
||||
}
|
||||
|
||||
#endregion 连接
|
||||
|
||||
#region 重写
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override Task InputMqttConnAckMessageAsync(MqttConnAckMessage message, CancellationToken cancellationToken)
|
||||
{
|
||||
this.m_waitForConnect?.SetResult(message);
|
||||
return EasyTask.CompletedTask;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override Task InputMqttConnectMessageAsync(MqttConnectMessage message, CancellationToken cancellationToken)
|
||||
{
|
||||
throw ThrowHelper.CreateNotSupportedException($"遇到无法处理的数据报文,Message={message}");
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override Task InputMqttPingRespMessageAsync(MqttPingRespMessage message, CancellationToken cancellationToken)
|
||||
{
|
||||
this.m_waitForPing.Set(message);
|
||||
return EasyTask.CompletedTask;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override Task InputMqttSubscribeMessageAsync(MqttSubscribeMessage message, CancellationToken cancellationToken)
|
||||
{
|
||||
throw ThrowHelper.CreateNotSupportedException($"遇到无法处理的数据报文,Message={message}");
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override Task InputMqttUnsubscribeMessageAsync(MqttUnsubscribeMessage message, CancellationToken cancellationToken)
|
||||
{
|
||||
throw ThrowHelper.CreateNotSupportedException($"遇到无法处理的数据报文,Message={message}");
|
||||
@@ -99,6 +116,12 @@ public sealed class MqttClientActor : MqttActor
|
||||
|
||||
#endregion 重写
|
||||
|
||||
/// <summary>
|
||||
/// 异步订阅。
|
||||
/// </summary>
|
||||
/// <param name="message">订阅消息。</param>
|
||||
/// <param name="cancellationToken">取消令牌。</param>
|
||||
/// <returns>订阅确认消息。</returns>
|
||||
public async Task<MqttSubAckMessage> SubscribeAsync(MqttSubscribeMessage message, CancellationToken cancellationToken = default)
|
||||
{
|
||||
using (var waitDataAsync = this.WaitHandlePool.GetWaitDataAsync(message))
|
||||
@@ -112,6 +135,12 @@ public sealed class MqttClientActor : MqttActor
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步取消订阅。
|
||||
/// </summary>
|
||||
/// <param name="message">取消订阅消息。</param>
|
||||
/// <param name="cancellationToken">取消令牌。</param>
|
||||
/// <returns>取消订阅确认消息。</returns>
|
||||
public async Task<MqttUnsubAckMessage> UnsubscribeAsync(MqttUnsubscribeMessage message, CancellationToken cancellationToken = default)
|
||||
{
|
||||
using (var waitDataAsync = this.WaitHandlePool.GetWaitDataAsync(message))
|
||||
|
||||
@@ -44,8 +44,8 @@ public abstract class RpcAttribute : Attribute
|
||||
/// 生成代码
|
||||
/// </summary>
|
||||
public CodeGeneratorFlag GeneratorFlag { get; set; } =
|
||||
CodeGeneratorFlag.InstanceSync | CodeGeneratorFlag.InstanceAsync | CodeGeneratorFlag.ExtensionSync | CodeGeneratorFlag.ExtensionAsync
|
||||
| CodeGeneratorFlag.InterfaceSync | CodeGeneratorFlag.InterfaceAsync;
|
||||
CodeGeneratorFlag.InstanceAsync | CodeGeneratorFlag.ExtensionAsync
|
||||
| CodeGeneratorFlag.InterfaceAsync;
|
||||
|
||||
/// <summary>
|
||||
/// 生成泛型方法的约束
|
||||
@@ -85,11 +85,7 @@ public abstract class RpcAttribute : Attribute
|
||||
public virtual string GetDescription(RpcMethod rpcMethod)
|
||||
{
|
||||
var description = rpcMethod.GetDescription();
|
||||
if (description.HasValue())
|
||||
{
|
||||
return this.ReplacePatterns(description);
|
||||
}
|
||||
return "无注释信息";
|
||||
return description.HasValue() ? this.ReplacePatterns(description) : "无注释信息";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -105,56 +101,56 @@ public abstract class RpcAttribute : Attribute
|
||||
|
||||
var parametersStr = this.GetParameters(rpcMethod, out var parameters);
|
||||
var InterfaceTypes = this.GetGenericConstraintTypes();
|
||||
if (this.GeneratorFlag.HasFlag(CodeGeneratorFlag.ExtensionSync))
|
||||
{
|
||||
codeString.AppendLine("///<summary>");
|
||||
codeString.AppendLine($"///{description}");
|
||||
codeString.AppendLine("///</summary>");
|
||||
foreach (var item in this.Exceptions)
|
||||
{
|
||||
codeString.AppendLine($"/// <exception cref=\"{item.Key.FullName}\">{item.Value}</exception>");
|
||||
}
|
||||
//if (this.GeneratorFlag.HasFlag(CodeGeneratorFlag.ExtensionSync))
|
||||
//{
|
||||
// codeString.AppendLine("///<summary>");
|
||||
// codeString.AppendLine($"///{description}");
|
||||
// codeString.AppendLine("///</summary>");
|
||||
// foreach (var item in this.Exceptions)
|
||||
// {
|
||||
// codeString.AppendLine($"/// <exception cref=\"{item.Key.FullName}\">{item.Value}</exception>");
|
||||
// }
|
||||
|
||||
codeString.AppendLine("[AsyncToSyncWarning]");
|
||||
codeString.Append("public static ");
|
||||
codeString.Append(this.GetReturn(rpcMethod, false));
|
||||
codeString.Append(' ');
|
||||
codeString.Append(this.GetMethodName(rpcMethod, false));
|
||||
codeString.Append("<TClient>(");//方法参数
|
||||
// codeString.AppendLine("[AsyncToSyncWarning]");
|
||||
// codeString.Append("public static ");
|
||||
// codeString.Append(this.GetReturn(rpcMethod, false));
|
||||
// codeString.Append(' ');
|
||||
// codeString.Append(this.GetMethodName(rpcMethod, false));
|
||||
// codeString.Append("<TClient>(");//方法参数
|
||||
|
||||
codeString.Append($"this TClient client");
|
||||
// codeString.Append($"this TClient client");
|
||||
|
||||
codeString.Append(',');
|
||||
for (var i = 0; i < parametersStr.Count; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
codeString.Append(',');
|
||||
}
|
||||
// codeString.Append(',');
|
||||
// for (var i = 0; i < parametersStr.Count; i++)
|
||||
// {
|
||||
// if (i > 0)
|
||||
// {
|
||||
// codeString.Append(',');
|
||||
// }
|
||||
|
||||
codeString.Append(parametersStr[i]);
|
||||
}
|
||||
if (parametersStr.Count > 0)
|
||||
{
|
||||
codeString.Append(',');
|
||||
}
|
||||
codeString.Append(this.GetInvokeOption());
|
||||
codeString.AppendLine(") where TClient:");
|
||||
// codeString.Append(parametersStr[i]);
|
||||
// }
|
||||
// if (parametersStr.Count > 0)
|
||||
// {
|
||||
// codeString.Append(',');
|
||||
// }
|
||||
// codeString.Append(this.GetInvokeOption());
|
||||
// codeString.AppendLine(") where TClient:");
|
||||
|
||||
for (var i = 0; i < InterfaceTypes.Length; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
codeString.Append(',');
|
||||
}
|
||||
// for (var i = 0; i < InterfaceTypes.Length; i++)
|
||||
// {
|
||||
// if (i > 0)
|
||||
// {
|
||||
// codeString.Append(',');
|
||||
// }
|
||||
|
||||
codeString.Append(InterfaceTypes[i].FullName);
|
||||
}
|
||||
// codeString.Append(InterfaceTypes[i].FullName);
|
||||
// }
|
||||
|
||||
codeString.AppendLine("{");//方法开始
|
||||
codeString.AppendLine(this.GetExtensionInstanceMethod(rpcMethod, parametersStr, parameters, false));
|
||||
codeString.AppendLine("}");
|
||||
}
|
||||
// codeString.AppendLine("{");//方法开始
|
||||
// codeString.AppendLine(this.GetExtensionInstanceMethod(rpcMethod, parametersStr, parameters, false));
|
||||
// codeString.AppendLine("}");
|
||||
//}
|
||||
|
||||
//以下生成异步
|
||||
if (this.GeneratorFlag.HasFlag(CodeGeneratorFlag.ExtensionAsync))
|
||||
@@ -232,43 +228,43 @@ public abstract class RpcAttribute : Attribute
|
||||
|
||||
var description = this.GetDescription(rpcMethod);
|
||||
var parametersStr = this.GetParameters(rpcMethod, out var parameters);
|
||||
if (this.GeneratorFlag.HasFlag(CodeGeneratorFlag.InstanceSync))
|
||||
{
|
||||
codeString.AppendLine("///<summary>");
|
||||
codeString.AppendLine($"///{description}");
|
||||
codeString.AppendLine("///</summary>");
|
||||
foreach (var item in this.Exceptions)
|
||||
{
|
||||
codeString.AppendLine($"/// <exception cref=\"{item.Key.FullName}\">{item.Value}</exception>");
|
||||
}
|
||||
codeString.AppendLine("[AsyncToSyncWarning]");
|
||||
codeString.Append("public ");
|
||||
codeString.Append(this.GetReturn(rpcMethod, false));
|
||||
codeString.Append(' ');
|
||||
codeString.Append(this.GetMethodName(rpcMethod, false));
|
||||
codeString.Append('(');//方法参数
|
||||
//if (this.GeneratorFlag.HasFlag(CodeGeneratorFlag.InstanceSync))
|
||||
//{
|
||||
// codeString.AppendLine("///<summary>");
|
||||
// codeString.AppendLine($"///{description}");
|
||||
// codeString.AppendLine("///</summary>");
|
||||
// foreach (var item in this.Exceptions)
|
||||
// {
|
||||
// codeString.AppendLine($"/// <exception cref=\"{item.Key.FullName}\">{item.Value}</exception>");
|
||||
// }
|
||||
// codeString.AppendLine("[AsyncToSyncWarning]");
|
||||
// codeString.Append("public ");
|
||||
// codeString.Append(this.GetReturn(rpcMethod, false));
|
||||
// codeString.Append(' ');
|
||||
// codeString.Append(this.GetMethodName(rpcMethod, false));
|
||||
// codeString.Append('(');//方法参数
|
||||
|
||||
for (var i = 0; i < parametersStr.Count; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
codeString.Append(',');
|
||||
}
|
||||
codeString.Append(parametersStr[i]);
|
||||
}
|
||||
if (parametersStr.Count > 0)
|
||||
{
|
||||
codeString.Append(',');
|
||||
}
|
||||
codeString.Append(this.GetInvokeOption());
|
||||
codeString.AppendLine(")");
|
||||
// for (var i = 0; i < parametersStr.Count; i++)
|
||||
// {
|
||||
// if (i > 0)
|
||||
// {
|
||||
// codeString.Append(',');
|
||||
// }
|
||||
// codeString.Append(parametersStr[i]);
|
||||
// }
|
||||
// if (parametersStr.Count > 0)
|
||||
// {
|
||||
// codeString.Append(',');
|
||||
// }
|
||||
// codeString.Append(this.GetInvokeOption());
|
||||
// codeString.AppendLine(")");
|
||||
|
||||
codeString.AppendLine("{");//方法开始
|
||||
// codeString.AppendLine("{");//方法开始
|
||||
|
||||
codeString.AppendLine(this.GetInstanceMethod(rpcMethod, parametersStr, parameters, false));
|
||||
// codeString.AppendLine(this.GetInstanceMethod(rpcMethod, parametersStr, parameters, false));
|
||||
|
||||
codeString.AppendLine("}");
|
||||
}
|
||||
// codeString.AppendLine("}");
|
||||
//}
|
||||
|
||||
//以下生成异步
|
||||
if (this.GeneratorFlag.HasFlag(CodeGeneratorFlag.InstanceAsync))
|
||||
@@ -324,36 +320,36 @@ public abstract class RpcAttribute : Attribute
|
||||
var codeString = new StringBuilder();
|
||||
var description = this.GetDescription(rpcMethod);
|
||||
var parameters = this.GetParameters(rpcMethod, out _);
|
||||
if (this.GeneratorFlag.HasFlag(CodeGeneratorFlag.InterfaceSync))
|
||||
{
|
||||
codeString.AppendLine("///<summary>");
|
||||
codeString.AppendLine($"///{description}");
|
||||
codeString.AppendLine("///</summary>");
|
||||
foreach (var item in this.Exceptions)
|
||||
{
|
||||
codeString.AppendLine($"/// <exception cref=\"{item.Key.FullName}\">{item.Value}</exception>");
|
||||
}
|
||||
//if (this.GeneratorFlag.HasFlag(CodeGeneratorFlag.InterfaceSync))
|
||||
//{
|
||||
// codeString.AppendLine("///<summary>");
|
||||
// codeString.AppendLine($"///{description}");
|
||||
// codeString.AppendLine("///</summary>");
|
||||
// foreach (var item in this.Exceptions)
|
||||
// {
|
||||
// codeString.AppendLine($"/// <exception cref=\"{item.Key.FullName}\">{item.Value}</exception>");
|
||||
// }
|
||||
|
||||
codeString.AppendLine("[AsyncToSyncWarning]");
|
||||
codeString.Append(this.GetReturn(rpcMethod, false));
|
||||
codeString.Append(' ');
|
||||
codeString.Append(this.GetMethodName(rpcMethod, false));
|
||||
codeString.Append('(');//方法参数
|
||||
for (var i = 0; i < parameters.Count; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
codeString.Append(',');
|
||||
}
|
||||
codeString.Append(parameters[i]);
|
||||
}
|
||||
if (parameters.Count > 0)
|
||||
{
|
||||
codeString.Append(',');
|
||||
}
|
||||
codeString.Append(this.GetInvokeOption());
|
||||
codeString.AppendLine(");");
|
||||
}
|
||||
// codeString.AppendLine("[AsyncToSyncWarning]");
|
||||
// codeString.Append(this.GetReturn(rpcMethod, false));
|
||||
// codeString.Append(' ');
|
||||
// codeString.Append(this.GetMethodName(rpcMethod, false));
|
||||
// codeString.Append('(');//方法参数
|
||||
// for (var i = 0; i < parameters.Count; i++)
|
||||
// {
|
||||
// if (i > 0)
|
||||
// {
|
||||
// codeString.Append(',');
|
||||
// }
|
||||
// codeString.Append(parameters[i]);
|
||||
// }
|
||||
// if (parameters.Count > 0)
|
||||
// {
|
||||
// codeString.Append(',');
|
||||
// }
|
||||
// codeString.Append(this.GetInvokeOption());
|
||||
// codeString.AppendLine(");");
|
||||
//}
|
||||
|
||||
if (this.GeneratorFlag.HasFlag(CodeGeneratorFlag.InterfaceAsync))
|
||||
{
|
||||
@@ -396,14 +392,9 @@ public abstract class RpcAttribute : Attribute
|
||||
/// <returns></returns>
|
||||
public virtual string GetInvokeKey(RpcMethod rpcMethod)
|
||||
{
|
||||
if (this.MethodInvoke)
|
||||
{
|
||||
return this.GetMethodName(rpcMethod, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
return !this.InvokeKey.IsNullOrEmpty() ? this.InvokeKey : $"{rpcMethod.ServerFromType.FullName}.{rpcMethod.Name}".ToLower();
|
||||
}
|
||||
return this.MethodInvoke
|
||||
? this.GetMethodName(rpcMethod, false)
|
||||
: !this.InvokeKey.IsNullOrEmpty() ? this.InvokeKey : $"{rpcMethod.ServerFromType.FullName}.{rpcMethod.Name}".ToLower();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -424,32 +415,15 @@ public abstract class RpcAttribute : Attribute
|
||||
public virtual string GetMethodName(RpcMethod rpcMethod, bool isAsync)
|
||||
{
|
||||
var name = this.MethodName;
|
||||
if (name.HasValue())
|
||||
{
|
||||
name = this.ReplacePatterns(name).Format(rpcMethod.Name);
|
||||
}
|
||||
else
|
||||
{
|
||||
name = rpcMethod.Name;
|
||||
}
|
||||
name = name.HasValue() ? this.ReplacePatterns(name).Format(rpcMethod.Name) : rpcMethod.Name;
|
||||
|
||||
if (isAsync)
|
||||
{
|
||||
if (name.EndsWith("Async"))
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
return $"{name}Async";
|
||||
return name.EndsWith("Async") ? name : $"{name}Async";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (name.EndsWith("Async"))
|
||||
{
|
||||
return name.RemoveLastChars(5);
|
||||
}
|
||||
|
||||
return name;
|
||||
return name.EndsWith("Async") ? name.RemoveLastChars(5) : name;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -341,15 +341,15 @@ public static class CodeGenerator
|
||||
rpcAttribute.SetClassCodeGenerator(classCodeGenerator);
|
||||
if (first)
|
||||
{
|
||||
if (rpcAttribute.GeneratorFlag.HasFlag(CodeGeneratorFlag.InterfaceAsync) || rpcAttribute.GeneratorFlag.HasFlag(CodeGeneratorFlag.InterfaceSync))
|
||||
if (rpcAttribute.GeneratorFlag.HasFlag(CodeGeneratorFlag.InterfaceAsync))
|
||||
{
|
||||
serverCellCode.IncludeInterface = true;
|
||||
}
|
||||
if (rpcAttribute.GeneratorFlag.HasFlag(CodeGeneratorFlag.InstanceAsync) || rpcAttribute.GeneratorFlag.HasFlag(CodeGeneratorFlag.InstanceSync))
|
||||
if (rpcAttribute.GeneratorFlag.HasFlag(CodeGeneratorFlag.InstanceAsync))
|
||||
{
|
||||
serverCellCode.IncludeInstance = true;
|
||||
}
|
||||
if (rpcAttribute.GeneratorFlag.HasFlag(CodeGeneratorFlag.ExtensionAsync) || rpcAttribute.GeneratorFlag.HasFlag(CodeGeneratorFlag.ExtensionSync))
|
||||
if (rpcAttribute.GeneratorFlag.HasFlag(CodeGeneratorFlag.ExtensionAsync))
|
||||
{
|
||||
serverCellCode.IncludeExtension = true;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ public enum CodeGeneratorFlag
|
||||
/// <summary>
|
||||
/// 生成扩展同步代码
|
||||
/// </summary>
|
||||
[Obsolete("此配置已被弃用,目前已经不再支持同步代码生成", true)]
|
||||
ExtensionSync = 1,
|
||||
|
||||
/// <summary>
|
||||
@@ -31,6 +32,7 @@ public enum CodeGeneratorFlag
|
||||
/// <summary>
|
||||
/// 生成实例类同步代码(源代码生成无效)
|
||||
/// </summary>
|
||||
[Obsolete("此配置已被弃用,目前已经不再支持同步代码生成", true)]
|
||||
InstanceSync = 4,
|
||||
|
||||
/// <summary>
|
||||
@@ -41,6 +43,7 @@ public enum CodeGeneratorFlag
|
||||
/// <summary>
|
||||
/// 生成接口同步代码
|
||||
/// </summary>
|
||||
[Obsolete("此配置已被弃用,目前已经不再支持同步代码生成", true)]
|
||||
InterfaceSync = 16,
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -24,10 +24,12 @@ public class TransportOption
|
||||
/// </summary>
|
||||
public TransportOption()
|
||||
{
|
||||
this.ReceivePipeOptions = CreateDefaultPipeOptions();
|
||||
this.SendPipeOptions = CreateDefaultPipeOptions();
|
||||
this.ReceivePipeOptions = CreateDefaultReadPipeOptions();
|
||||
this.SendPipeOptions = CreateDefaultWritePipeOptions();
|
||||
}
|
||||
|
||||
public bool BufferOnDemand { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置最大缓冲区大小(字节)。
|
||||
/// </summary>
|
||||
@@ -48,25 +50,8 @@ public class TransportOption
|
||||
/// </summary>
|
||||
public PipeOptions SendPipeOptions { get; set; }
|
||||
|
||||
public bool BufferOnDemand { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// 创建默认的 <see cref="PipeOptions"/>。
|
||||
/// </summary>
|
||||
public static PipeOptions CreateDefaultPipeOptions()
|
||||
{
|
||||
return new PipeOptions(
|
||||
pool: null,
|
||||
readerScheduler: null,
|
||||
writerScheduler: null,
|
||||
pauseWriterThreshold: -1,
|
||||
resumeWriterThreshold: -1,
|
||||
minimumSegmentSize: -1,
|
||||
useSynchronizationContext: true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建注重调度的 <see cref="PipeOptions"/>,适合需要主线程调度的场景。
|
||||
/// 创建注重调度的 <see cref="PipeOptions"/>。
|
||||
/// </summary>
|
||||
public static PipeOptions CreateSchedulerOptimizedPipeOptions()
|
||||
{
|
||||
@@ -74,9 +59,33 @@ public class TransportOption
|
||||
pool: null,
|
||||
readerScheduler: PipeScheduler.Inline,
|
||||
writerScheduler: PipeScheduler.Inline,
|
||||
pauseWriterThreshold: -1,
|
||||
resumeWriterThreshold: -1,
|
||||
pauseWriterThreshold: 1024 * 64,
|
||||
resumeWriterThreshold: 1024 * 32,
|
||||
minimumSegmentSize: -1,
|
||||
useSynchronizationContext: false);
|
||||
}
|
||||
|
||||
private static PipeOptions CreateDefaultReadPipeOptions()
|
||||
{
|
||||
return new PipeOptions(
|
||||
pool: null,
|
||||
readerScheduler: PipeScheduler.ThreadPool,
|
||||
writerScheduler: PipeScheduler.ThreadPool,
|
||||
pauseWriterThreshold: 1024 * 1024,
|
||||
resumeWriterThreshold: 1024 * 512,
|
||||
minimumSegmentSize: -1,
|
||||
useSynchronizationContext: true);
|
||||
}
|
||||
|
||||
private static PipeOptions CreateDefaultWritePipeOptions()
|
||||
{
|
||||
return new PipeOptions(
|
||||
pool: null,
|
||||
readerScheduler: PipeScheduler.ThreadPool,
|
||||
writerScheduler: PipeScheduler.ThreadPool,
|
||||
pauseWriterThreshold: 64 * 1024,
|
||||
resumeWriterThreshold: 32 * 1024,
|
||||
minimumSegmentSize: -1,
|
||||
useSynchronizationContext: true);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user