mirror of
https://gitee.com/ThingsGateway/ThingsGateway.git
synced 2025-10-23 03:50:30 +08:00
Compare commits
11 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
1c52be8b47 | ||
![]() |
bcd82055ca | ||
![]() |
c47d95d170 | ||
![]() |
3e62f1ad51 | ||
![]() |
8dcae973ef | ||
![]() |
4cf35f7294 | ||
![]() |
94c77d151b | ||
![]() |
7f600e2b4b | ||
![]() |
c809d0ba87 | ||
![]() |
50f038ec89 | ||
![]() |
9199a255a2 |
@@ -1,6 +1,6 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<Version>3.0.0.28</Version>
|
||||
<Version>3.0.1.0</Version>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Authors>Diego</Authors>
|
||||
<Product>ThingsGateway</Product>
|
||||
|
@@ -10,7 +10,6 @@
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
|
||||
using System.Drawing;
|
||||
|
||||
namespace ThingsGateway.Foundation.Demo.Winform
|
||||
|
@@ -1,12 +1,12 @@
|
||||
#region copyright
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊȫ<EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD>ֶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
// <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><EFBFBD>룩<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߱<EFBFBD><EFBFBD><EFBFBD>Diego<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
// Դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѭ<EFBFBD><EFBFBD><EFBFBD>ֿ<EFBFBD><EFBFBD>Ŀ<EFBFBD>ԴЭ<EFBFBD>鼰<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD>
|
||||
// GiteeԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://gitee.com/diego2098/ThingsGateway
|
||||
// GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway
|
||||
// ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQȺ<EFBFBD><EFBFBD>605534569
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
|
@@ -1,4 +1,14 @@
|
||||
using System.Windows.Forms;
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace ThingsGateway.Foundation.Demo.Winform
|
||||
{
|
||||
|
@@ -21,7 +21,7 @@
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebView.WindowsForms" Version="7.0.96" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebView.WindowsForms" Version="7.0.100" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<Version>3.0.0.28</Version>
|
||||
<Version>3.0.1.0</Version>
|
||||
<GenerateDocumentationFile>True</GenerateDocumentationFile>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<TargetFrameworks>net45;netstandard2.0;net6.0;net7.0</TargetFrameworks>
|
||||
|
@@ -459,6 +459,7 @@ namespace ThingsGateway.Foundation.Adapter.Siemens
|
||||
if (!result1.IsSuccess)
|
||||
{
|
||||
Logger?.Warning($"{client.IP} : {client.Port}:ISO_TP握手失败-{result1.Message}");
|
||||
TcpClient.Close();
|
||||
return;
|
||||
}
|
||||
var result2 = await SendThenResponseAsync(S7_PN);
|
||||
|
@@ -207,7 +207,7 @@ public interface IReadWrite : IDisposable
|
||||
/// <summary>
|
||||
/// 读写超时时间
|
||||
/// </summary>
|
||||
ushort TimeOut { get; set; }
|
||||
int TimeOut { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 一个寄存器所占的字节长度
|
||||
|
@@ -54,7 +54,7 @@ public abstract class ReadWriteDevicesBase : IReadWrite
|
||||
|
||||
/// <inheritdoc/>
|
||||
[Description("读写超时时间")]
|
||||
public ushort TimeOut { get; set; } = 3000;
|
||||
public int TimeOut { get; set; } = 3000;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool CascadeDisposal { get; set; } = true;
|
||||
|
@@ -72,4 +72,28 @@ namespace ThingsGateway.Foundation.Core
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
#if NET6_0_OR_GREATER
|
||||
public partial class DisposableObject : IAsyncDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// 异步释放资源。内部已经处理了<see cref="GC.SuppressFinalize(object)"/>
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async ValueTask DisposeAsync()
|
||||
{
|
||||
await DisposeAsyncCore().ConfigureAwait(false);
|
||||
Dispose(disposing: false);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步释放资源。注意:此方法仅在调用<see cref="IAsyncDisposable.DisposeAsync"/>时有效。
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected virtual ValueTask DisposeAsyncCore()
|
||||
{
|
||||
return ValueTask.CompletedTask;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
@@ -1,4 +1,4 @@
|
||||
#region copyright
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
@@ -10,24 +10,17 @@
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace ThingsGateway.Foundation.Serial;
|
||||
|
||||
/// <summary>
|
||||
/// 通讯基类
|
||||
/// </summary>
|
||||
public abstract class BaseSerial : DependencyObject, ISerial
|
||||
namespace ThingsGateway.Foundation.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// 同步根。
|
||||
/// 具有配置设置的对象
|
||||
/// </summary>
|
||||
protected readonly object SyncRoot = new object();
|
||||
public abstract class ConfigObject : DependencyObject, IConfigObject
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public abstract TouchSocketConfig Config { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public abstract int SendBufferSize { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public abstract int ReceiveBufferSize { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ILog Logger { get; set; }
|
||||
/// <inheritdoc/>
|
||||
public ILog Logger { get; set; }
|
||||
}
|
||||
}
|
@@ -1,4 +1,4 @@
|
||||
#region copyright
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
@@ -10,12 +10,16 @@
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace ThingsGateway.Foundation.Serial;
|
||||
|
||||
/// <summary>
|
||||
/// 串口基接口
|
||||
/// </summary>
|
||||
public interface ISerial : ISocket
|
||||
namespace ThingsGateway.Foundation.Core
|
||||
{
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// 具有配置的对象接口
|
||||
/// </summary>
|
||||
public interface IConfigObject : IDependencyObject, ILoggerObject
|
||||
{
|
||||
/// <summary>
|
||||
/// 设置项
|
||||
/// </summary>
|
||||
TouchSocketConfig Config { get; }
|
||||
}
|
||||
}
|
@@ -0,0 +1,48 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:http://rrqm_home.gitee.io/touchsocket/
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace ThingsGateway.Foundation.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// 当配置Config完成时触发。
|
||||
/// </summary>
|
||||
public interface ILoadedConfigPlugin<in TSender> : IPlugin where TSender : IConfigObject
|
||||
{
|
||||
/// <summary>
|
||||
/// 当完成配置载入时
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
/// <returns></returns>
|
||||
Task OnLoadedConfig(TSender sender, ConfigEventArgs e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当配置Config完成时触发。
|
||||
/// </summary>
|
||||
public interface ILoadedConfigPlugin : ILoadedConfigPlugin<IConfigObject>
|
||||
{
|
||||
}
|
||||
}
|
@@ -0,0 +1,34 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace ThingsGateway.Foundation.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// 当正在配置Config时触发。
|
||||
/// </summary>
|
||||
public interface ILoadingConfigPlugin<in TSender> : IPlugin where TSender : IConfigObject
|
||||
{
|
||||
/// <summary>
|
||||
/// 当载入配置时
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
Task OnLoadingConfig(TSender sender, ConfigEventArgs e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ILoadingConfigPlugin
|
||||
/// </summary>
|
||||
public interface ILoadingConfigPlugin : ILoadingConfigPlugin<IConfigObject>
|
||||
{
|
||||
}
|
||||
}
|
@@ -0,0 +1,27 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace ThingsGateway.Foundation.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// 具有设置配置的对象接口
|
||||
/// </summary>
|
||||
public interface ISetupConfigObject : IConfigObject, IPluginObject
|
||||
{
|
||||
/// <summary>
|
||||
/// 配置设置项
|
||||
/// </summary>
|
||||
/// <param name="config"></param>
|
||||
/// <exception cref="Exception"></exception>
|
||||
void Setup(TouchSocketConfig config);
|
||||
}
|
||||
}
|
@@ -0,0 +1,102 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace ThingsGateway.Foundation.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// 具有设置配置的对象
|
||||
/// </summary>
|
||||
public abstract class SetupConfigObject : ConfigObject, ISetupConfigObject
|
||||
{
|
||||
private TouchSocketConfig m_config;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override TouchSocketConfig Config => this.m_config;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IContainer Container { get; private set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IPluginsManager PluginsManager { get; private set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Setup(TouchSocketConfig config)
|
||||
{
|
||||
if (config == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(config));
|
||||
}
|
||||
|
||||
this.ThrowIfDisposed();
|
||||
|
||||
this.BuildConfig(config);
|
||||
|
||||
this.PluginsManager?.Raise(nameof(ILoadingConfigPlugin.OnLoadingConfig), this, new ConfigEventArgs(config));
|
||||
this.LoadConfig(this.Config);
|
||||
this.PluginsManager?.Raise(nameof(ILoadedConfigPlugin.OnLoadedConfig), this, new ConfigEventArgs(config));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 加载配置
|
||||
/// </summary>
|
||||
/// <param name="config"></param>
|
||||
protected virtual void LoadConfig(TouchSocketConfig config)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private void BuildConfig(TouchSocketConfig config)
|
||||
{
|
||||
this.m_config = config;
|
||||
|
||||
if (!config.TryGetValue(TouchSocketCoreConfigExtension.ContainerProperty, out var container))
|
||||
{
|
||||
container = new Container();
|
||||
}
|
||||
|
||||
if (!container.IsRegistered(typeof(ILog)))
|
||||
{
|
||||
container.RegisterSingleton<ILog, LoggerGroup>();
|
||||
}
|
||||
|
||||
if (!(config.GetValue(TouchSocketCoreConfigExtension.PluginsManagerProperty) is IPluginsManager pluginsManager))
|
||||
{
|
||||
pluginsManager = new PluginsManager(container);
|
||||
}
|
||||
|
||||
if (container.IsRegistered(typeof(IPluginsManager)))
|
||||
{
|
||||
pluginsManager = container.Resolve<IPluginsManager>();
|
||||
}
|
||||
else
|
||||
{
|
||||
container.RegisterSingleton<IPluginsManager>(pluginsManager);
|
||||
}
|
||||
|
||||
if (config.GetValue(TouchSocketCoreConfigExtension.ConfigureContainerProperty) is Action<IContainer> actionContainer)
|
||||
{
|
||||
actionContainer.Invoke(container);
|
||||
}
|
||||
|
||||
if (config.GetValue(TouchSocketCoreConfigExtension.ConfigurePluginsProperty) is Action<IPluginsManager> actionPluginsManager)
|
||||
{
|
||||
pluginsManager.Enable = true;
|
||||
actionPluginsManager.Invoke(pluginsManager);
|
||||
}
|
||||
|
||||
this.Logger ??= container.Resolve<ILog>();
|
||||
|
||||
this.Container = container;
|
||||
this.PluginsManager = pluginsManager;
|
||||
}
|
||||
}
|
||||
}
|
@@ -28,8 +28,22 @@ namespace ThingsGateway.Foundation.Core
|
||||
/// <summary>
|
||||
/// 配置文件基类
|
||||
/// </summary>
|
||||
public class TouchSocketConfig : DependencyObject
|
||||
public class TouchSocketConfig : DependencyObject, ICloneable
|
||||
{
|
||||
/// <summary>
|
||||
/// 克隆配置依赖项,并返回一个新的克隆对象。
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public TouchSocketConfig Clone()
|
||||
{
|
||||
var config = new TouchSocketConfig();
|
||||
this.CloneTo(config, true);
|
||||
return config;
|
||||
}
|
||||
|
||||
object ICloneable.Clone()
|
||||
{
|
||||
return this.Clone();
|
||||
}
|
||||
}
|
||||
}
|
@@ -28,17 +28,17 @@ namespace ThingsGateway.Foundation.Core
|
||||
/// <summary>
|
||||
/// 单线程流式适配器配置
|
||||
/// </summary>
|
||||
public class SingleStreamAdapterOption
|
||||
public class AdapterOption
|
||||
{
|
||||
/// <summary>
|
||||
/// 适配器数据包缓存启用。默认为缺省(null),如果有正常值会在设置适配器时,直接作用于<see cref="SingleStreamDataHandlingAdapter.CacheTimeout"/>
|
||||
/// </summary>
|
||||
public bool? CacheTimeoutEnable { get; set; } = true;
|
||||
public bool? CacheTimeoutEnable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 适配器数据包缓存时长。默认为缺省(null)。当该值有效时会在设置适配器时,直接作用于<see cref="SingleStreamDataHandlingAdapter.CacheTimeout"/>
|
||||
/// </summary>
|
||||
public int? CacheTimeout { get; set; }
|
||||
public TimeSpan? CacheTimeout { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 适配器数据包最大值。默认缺省(null),当该值有效时会在设置适配器时,直接作用于<see cref="DataHandlingAdapter.MaxPackageSize"/>
|
@@ -26,92 +26,62 @@ namespace ThingsGateway.Foundation.Core
|
||||
/// <param name="config"></param>
|
||||
public static void Config(this SingleStreamDataHandlingAdapter adapter, TouchSocketConfig config)
|
||||
{
|
||||
if (config.GetValue(DataHandlingAdapterExtension.MaxPackageSizeProperty) is int v1)
|
||||
var option = config.GetValue(AdapterOptionProperty) ?? throw new ArgumentNullException(nameof(AdapterOptionProperty));
|
||||
|
||||
if (option.MaxPackageSize.HasValue)
|
||||
{
|
||||
adapter.MaxPackageSize = v1;
|
||||
adapter.MaxPackageSize = option.MaxPackageSize.Value;
|
||||
}
|
||||
if (config.GetValue(DataHandlingAdapterExtension.CacheTimeoutProperty) != TimeSpan.Zero)
|
||||
|
||||
if (option.CacheTimeout.HasValue)
|
||||
{
|
||||
adapter.CacheTimeout = config.GetValue(DataHandlingAdapterExtension.CacheTimeoutProperty);
|
||||
adapter.CacheTimeout = option.CacheTimeout.Value;
|
||||
}
|
||||
if (config.GetValue(DataHandlingAdapterExtension.CacheTimeoutEnableProperty) is bool v2)
|
||||
|
||||
if (option.CacheTimeoutEnable.HasValue)
|
||||
{
|
||||
adapter.CacheTimeoutEnable = v2;
|
||||
adapter.CacheTimeoutEnable = option.CacheTimeoutEnable.Value;
|
||||
}
|
||||
if (config.GetValue(DataHandlingAdapterExtension.UpdateCacheTimeWhenRevProperty) is bool v3)
|
||||
|
||||
if (option.UpdateCacheTimeWhenRev.HasValue)
|
||||
{
|
||||
adapter.UpdateCacheTimeWhenRev = v3;
|
||||
adapter.UpdateCacheTimeWhenRev = option.UpdateCacheTimeWhenRev.Value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将<see cref="TouchSocketConfig"/>中的配置,装载在<see cref="SingleStreamDataHandlingAdapter"/>上。
|
||||
/// </summary>
|
||||
/// <param name="adapter"></param>
|
||||
/// <param name="config"></param>
|
||||
public static void Config(this DataHandlingAdapter adapter, TouchSocketConfig config)
|
||||
{
|
||||
var option = config.GetValue(AdapterOptionProperty) ?? throw new ArgumentNullException(nameof(AdapterOptionProperty));
|
||||
|
||||
if (option.MaxPackageSize.HasValue)
|
||||
{
|
||||
adapter.MaxPackageSize = option.MaxPackageSize.Value;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 适配器配置
|
||||
|
||||
/// <summary>
|
||||
/// 适配器数据包缓存启用。默认为缺省(null),如果有正常值会在设置适配器时,直接作用于<see cref="SingleStreamDataHandlingAdapter.CacheTimeout"/>
|
||||
/// 设置适配器相关的配置
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty<bool?> CacheTimeoutEnableProperty = DependencyProperty<bool?>.Register("CacheTimeoutEnable", null);
|
||||
public static readonly DependencyProperty<AdapterOption> AdapterOptionProperty = DependencyProperty<AdapterOption>.Register("AdapterOption", new AdapterOption());
|
||||
|
||||
/// <summary>
|
||||
/// 适配器数据包缓存时长。默认为缺省(<see cref="TimeSpan.Zero"/>)。当该值有效时会在设置适配器时,直接作用于<see cref="SingleStreamDataHandlingAdapter.CacheTimeout"/>
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty<TimeSpan> CacheTimeoutProperty = DependencyProperty<TimeSpan>.Register("CacheTimeout", TimeSpan.Zero);
|
||||
|
||||
/// <summary>
|
||||
/// 适配器数据包最大值。默认缺省(null),当该值有效时会在设置适配器时,直接作用于<see cref="DataHandlingAdapter.MaxPackageSize"/>
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty<int?> MaxPackageSizeProperty = DependencyProperty<int?>.Register("MaxPackageSize", null);
|
||||
|
||||
/// <summary>
|
||||
/// 适配器数据包缓存策略。默认缺省(null),当该值有效时会在设置适配器时,直接作用于<see cref="SingleStreamDataHandlingAdapter.UpdateCacheTimeWhenRev"/>
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty<bool?> UpdateCacheTimeWhenRevProperty = DependencyProperty<bool?>.Register("UpdateCacheTimeWhenRev", null);
|
||||
|
||||
/// <summary>
|
||||
/// 适配器数据包缓存时长。默认为缺省(<see cref="TimeSpan.Zero"/>)。当该值有效时会在设置适配器时,直接作用于<see cref="SingleStreamDataHandlingAdapter.CacheTimeout"/>
|
||||
/// 设置适配器相关的配置
|
||||
/// </summary>
|
||||
/// <param name="config"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static TouchSocketConfig SetCacheTimeout(this TouchSocketConfig config, TimeSpan value)
|
||||
public static TouchSocketConfig SetAdapterOption(this TouchSocketConfig config, AdapterOption value)
|
||||
{
|
||||
config.SetValue(CacheTimeoutProperty, value);
|
||||
return config;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 适配器数据包缓存启用。默认为缺省(null),如果有正常值会在设置适配器时,直接作用于<see cref="SingleStreamDataHandlingAdapter.CacheTimeoutEnable"/>
|
||||
/// </summary>
|
||||
/// <param name="config"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static TouchSocketConfig SetCacheTimeoutEnable(this TouchSocketConfig config, bool value)
|
||||
{
|
||||
config.SetValue(CacheTimeoutEnableProperty, value);
|
||||
return config;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 适配器数据包最大值。默认缺省(null),当该值有效时会在设置适配器时,直接作用于<see cref="DataHandlingAdapter.MaxPackageSize"/>
|
||||
/// </summary>
|
||||
/// <param name="config"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static TouchSocketConfig SetMaxPackageSize(this TouchSocketConfig config, int value)
|
||||
{
|
||||
config.SetValue(MaxPackageSizeProperty, value);
|
||||
return config;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 适配器数据包缓存策略。默认缺省(null),当该值有效时会在设置适配器时,直接作用于<see cref="SingleStreamDataHandlingAdapter.UpdateCacheTimeWhenRev"/>
|
||||
/// </summary>
|
||||
/// <param name="config"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static TouchSocketConfig SetUpdateCacheTimeWhenRev(this TouchSocketConfig config, bool value)
|
||||
{
|
||||
config.SetValue(UpdateCacheTimeWhenRevProperty, value);
|
||||
config.SetValue(AdapterOptionProperty, value);
|
||||
return config;
|
||||
}
|
||||
|
||||
|
@@ -96,5 +96,45 @@ namespace ThingsGateway.Foundation.Core
|
||||
this.m_dp.Clear();
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 将当前对象的依赖项克隆到目标对象中
|
||||
/// </summary>
|
||||
/// <param name="dependencyObject">目标对象</param>
|
||||
/// <param name="overwrite">当目标对象中存在相同依赖项时,是或否覆盖</param>
|
||||
/// <exception cref="ArgumentNullException"></exception>
|
||||
/// <exception cref="ObjectDisposedException"></exception>
|
||||
protected void CloneTo(DependencyObject dependencyObject, bool overwrite)
|
||||
{
|
||||
if (dependencyObject is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(dependencyObject));
|
||||
}
|
||||
|
||||
if (dependencyObject.DisposedValue)
|
||||
{
|
||||
throw new ObjectDisposedException(nameof(dependencyObject));
|
||||
}
|
||||
|
||||
this.ThrowIfDisposed();
|
||||
|
||||
foreach (var item in this.m_dp)
|
||||
{
|
||||
if (dependencyObject.m_dp.ContainsKey(item.Key))
|
||||
{
|
||||
if (overwrite)
|
||||
{
|
||||
dependencyObject.m_dp.Remove(item.Key);
|
||||
dependencyObject.m_dp.Add(item.Key, item.Value);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dependencyObject.m_dp.Add(item.Key, item.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -73,5 +73,48 @@ namespace ThingsGateway.Foundation.Core
|
||||
return task.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步等待指定最大时间
|
||||
/// </summary>
|
||||
/// <typeparam name="TResult"></typeparam>
|
||||
/// <param name="task"></param>
|
||||
/// <param name="timeout"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="TimeoutException"></exception>
|
||||
public static async Task<TResult> WaitAsync<TResult>(this Task<TResult> task, TimeSpan timeout)
|
||||
{
|
||||
using (var timeoutCancellationTokenSource = new CancellationTokenSource())
|
||||
{
|
||||
var delayTask = Task.Delay(timeout, timeoutCancellationTokenSource.Token);
|
||||
if (await Task.WhenAny(task, delayTask) == task)
|
||||
{
|
||||
timeoutCancellationTokenSource.Cancel();
|
||||
return await task;
|
||||
}
|
||||
throw new TimeoutException();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步等待指定最大时间
|
||||
/// </summary>
|
||||
/// <param name="task"></param>
|
||||
/// <param name="timeout"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="TimeoutException"></exception>
|
||||
public static async Task WaitAsync(this Task task, TimeSpan timeout)
|
||||
{
|
||||
using (var timeoutCancellationTokenSource = new CancellationTokenSource())
|
||||
{
|
||||
var delayTask = Task.Delay(timeout, timeoutCancellationTokenSource.Token);
|
||||
if (await Task.WhenAny(task, delayTask) == task)
|
||||
{
|
||||
timeoutCancellationTokenSource.Cancel();
|
||||
await task;
|
||||
return;
|
||||
}
|
||||
throw new TimeoutException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -23,23 +23,13 @@
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace ThingsGateway.Foundation.Sockets
|
||||
namespace ThingsGateway.Foundation.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Socket基接口
|
||||
/// 具有日志记录器的对象接口
|
||||
/// </summary>
|
||||
public interface ISocket : IDisposable
|
||||
public interface ILoggerObject
|
||||
{
|
||||
/// <summary>
|
||||
/// 发送缓存区大小。最小值=1024。
|
||||
/// </summary>
|
||||
int SendBufferSize { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 接收缓存区大小。最小值=1024。
|
||||
/// </summary>
|
||||
int ReceiveBufferSize { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 日志记录器
|
||||
/// </summary>
|
@@ -0,0 +1,49 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:http://rrqm_home.gitee.io/touchsocket/
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace ThingsGateway.Foundation.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// 序列化器
|
||||
/// </summary>
|
||||
/// <typeparam name="TSource"></typeparam>
|
||||
public interface ISerializer<TSource>
|
||||
{
|
||||
/// <summary>
|
||||
/// 序列化
|
||||
/// </summary>
|
||||
/// <param name="target"></param>
|
||||
/// <returns></returns>
|
||||
TSource Serialize(object target);
|
||||
|
||||
/// <summary>
|
||||
/// 反序列化
|
||||
/// </summary>
|
||||
/// <param name="source"></param>
|
||||
/// <param name="targetType"></param>
|
||||
/// <returns></returns>
|
||||
object Deserialize(TSource source, Type targetType);
|
||||
}
|
||||
}
|
@@ -15,7 +15,7 @@ namespace ThingsGateway.Foundation.Dmtp
|
||||
/// <summary>
|
||||
/// 提供Dmtp协议的最基础功能件
|
||||
/// </summary>
|
||||
public interface IDmtpActor : IDependencyObject
|
||||
public interface IDmtpActor : IDependencyObject, IHandshakeObject
|
||||
{
|
||||
#region 属性
|
||||
|
||||
@@ -39,11 +39,6 @@ namespace ThingsGateway.Foundation.Dmtp
|
||||
/// </summary>
|
||||
string Id { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前功能件是否已经完成握手连接状态。
|
||||
/// </summary>
|
||||
bool IsHandshaked { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 最后一次活动时间。
|
||||
/// </summary>
|
||||
|
@@ -0,0 +1,56 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:http://rrqm_home.gitee.io/touchsocket/
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace ThingsGateway.Foundation.Dmtp
|
||||
{
|
||||
/// <summary>
|
||||
/// 针对Dmtp的配置项
|
||||
/// </summary>
|
||||
public class DmtpOption
|
||||
{
|
||||
/// <summary>
|
||||
/// 连接令箭
|
||||
/// </summary>
|
||||
public string VerifyToken { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 连接时指定Id。
|
||||
/// <para>
|
||||
/// 使用该功能时,仅在服务器的Handshaking之后生效。且如果id重复,则会连接失败。
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public string Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 设置DmtpClient连接时的元数据
|
||||
/// </summary>
|
||||
public Metadata Metadata { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 验证连接超时时间。仅用于服务器。意为:当服务器收到基础链接,在指定的时间内如果没有收到握手信息,则直接视为无效链接,直接断开。
|
||||
/// </summary>
|
||||
public TimeSpan VerifyTimeout { get; set; } = TimeSpan.FromSeconds(3);
|
||||
}
|
||||
}
|
@@ -35,13 +35,13 @@ namespace ThingsGateway.Foundation.Dmtp
|
||||
private bool m_allowRoute;
|
||||
private Func<string, Task<IDmtpActor>> m_findDmtpActor;
|
||||
private DmtpActor m_dmtpActor;
|
||||
private readonly SemaphoreSlim m_semaphore = new SemaphoreSlim(1, 1);
|
||||
private readonly SemaphoreSlim m_semaphoreForConnect = new SemaphoreSlim(1, 1);
|
||||
#endregion 字段
|
||||
|
||||
/// <inheritdoc cref="IDmtpActor.Id"/>
|
||||
public string Id => this.m_dmtpActor.Id;
|
||||
|
||||
/// <inheritdoc cref="IDmtpActor.IsHandshaked"/>
|
||||
/// <inheritdoc cref="IHandshakeObject.IsHandshaked"/>
|
||||
public bool IsHandshaked => this.m_dmtpActor != null && this.m_dmtpActor.IsHandshaked;
|
||||
|
||||
/// <inheritdoc/>
|
||||
@@ -50,22 +50,23 @@ namespace ThingsGateway.Foundation.Dmtp
|
||||
#region 连接
|
||||
|
||||
/// <summary>
|
||||
/// 建立Tcp连接,并且执行握手。
|
||||
/// 使用基于Http升级的协议,连接Dmtp服务器
|
||||
/// </summary>
|
||||
/// <param name="timeout"></param>
|
||||
/// <returns></returns>
|
||||
/// <param name="token"></param>
|
||||
/// <exception cref="Exception"></exception>
|
||||
public override ITcpClient Connect(int timeout = 5000)
|
||||
public override void Connect(int timeout, CancellationToken token)
|
||||
{
|
||||
lock (this.SyncRoot)
|
||||
try
|
||||
{
|
||||
this.m_semaphoreForConnect.Wait(token);
|
||||
if (this.IsHandshaked)
|
||||
{
|
||||
return this;
|
||||
return;
|
||||
}
|
||||
if (!this.Online)
|
||||
{
|
||||
base.Connect(timeout);
|
||||
base.Connect(timeout, token);
|
||||
}
|
||||
|
||||
var request = new HttpRequest()
|
||||
@@ -78,72 +79,41 @@ namespace ThingsGateway.Foundation.Dmtp
|
||||
if (response.StatusCode == 101)
|
||||
{
|
||||
this.SwitchProtocolToDmtp();
|
||||
this.m_dmtpActor.Handshake(this.Config.GetValue(DmtpConfigExtension.VerifyTokenProperty),
|
||||
this.Config.GetValue(DmtpConfigExtension.DefaultIdProperty),
|
||||
timeout, this.Config.GetValue(DmtpConfigExtension.MetadataProperty), CancellationToken.None);
|
||||
return this;
|
||||
this.m_dmtpActor.Handshake(
|
||||
|
||||
this.Config.GetValue(DmtpConfigExtension.DmtpOptionProperty).VerifyToken, this.Config.GetValue(DmtpConfigExtension.DmtpOptionProperty).Id, timeout, this.Config.GetValue(DmtpConfigExtension.DmtpOptionProperty).Metadata, token);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception(response.StatusMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual IHttpDmtpClient Connect(CancellationToken token, int timeout = 5000)
|
||||
{
|
||||
lock (this.SyncRoot)
|
||||
finally
|
||||
{
|
||||
if (this.IsHandshaked)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
if (!this.Online)
|
||||
{
|
||||
base.Connect(timeout);
|
||||
}
|
||||
|
||||
var request = new HttpRequest()
|
||||
.SetHost(this.RemoteIPHost.Host);
|
||||
request.Headers.Add(HttpHeaders.Connection, "upgrade");
|
||||
request.Headers.Add(HttpHeaders.Upgrade, DmtpUtility.Dmtp.ToLower());
|
||||
|
||||
request.AsMethod(DmtpUtility.Dmtp);
|
||||
var response = this.RequestContent(request, timeout: timeout, token: token);
|
||||
if (response.StatusCode == 101)
|
||||
{
|
||||
this.SwitchProtocolToDmtp();
|
||||
this.m_dmtpActor.Handshake(this.Config.GetValue(DmtpConfigExtension.VerifyTokenProperty),
|
||||
this.Config.GetValue(DmtpConfigExtension.DefaultIdProperty),
|
||||
timeout, this.Config.GetValue(DmtpConfigExtension.MetadataProperty), token);
|
||||
return this;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception(response.StatusMessage);
|
||||
}
|
||||
this.m_semaphoreForConnect.Release();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 建立Tcp连接,并且执行握手。
|
||||
/// 异步使用基于Http升级的协议,连接Dmtp服务器
|
||||
/// </summary>
|
||||
/// <param name="timeout"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="Exception"></exception>
|
||||
public override async Task<ITcpClient> ConnectAsync(int timeout = 5000)
|
||||
public override async Task ConnectAsync(int timeout, CancellationToken token)
|
||||
{
|
||||
try
|
||||
{
|
||||
await this.m_semaphore.WaitAsync();
|
||||
await this.m_semaphoreForConnect.WaitAsync(timeout, token);
|
||||
if (this.IsHandshaked)
|
||||
{
|
||||
return this;
|
||||
return;
|
||||
}
|
||||
if (!this.Online)
|
||||
{
|
||||
await base.ConnectAsync(timeout);
|
||||
await base.ConnectAsync(timeout, token);
|
||||
}
|
||||
|
||||
var request = new HttpRequest()
|
||||
@@ -152,14 +122,12 @@ namespace ThingsGateway.Foundation.Dmtp
|
||||
request.Headers.Add(HttpHeaders.Upgrade, DmtpUtility.Dmtp.ToLower());
|
||||
|
||||
request.AsMethod(DmtpUtility.Dmtp);
|
||||
var response = this.RequestContent(request);
|
||||
var response = await this.RequestContentAsync(request);
|
||||
if (response.StatusCode == 101)
|
||||
{
|
||||
this.SwitchProtocolToDmtp();
|
||||
await this.m_dmtpActor.HandshakeAsync(this.Config.GetValue(DmtpConfigExtension.VerifyTokenProperty),
|
||||
this.Config.GetValue(DmtpConfigExtension.DefaultIdProperty),
|
||||
timeout, this.Config.GetValue(DmtpConfigExtension.MetadataProperty), CancellationToken.None);
|
||||
return this;
|
||||
await this.m_dmtpActor.HandshakeAsync(this.Config.GetValue(DmtpConfigExtension.DmtpOptionProperty).VerifyToken, this.Config.GetValue(DmtpConfigExtension.DmtpOptionProperty).Id, timeout, this.Config.GetValue(DmtpConfigExtension.DmtpOptionProperty).Metadata, token);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -168,48 +136,7 @@ namespace ThingsGateway.Foundation.Dmtp
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.m_semaphore.Release();
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual async Task<IHttpDmtpClient> ConnectAsync(CancellationToken token, int timeout = 5000)
|
||||
{
|
||||
try
|
||||
{
|
||||
await this.m_semaphore.WaitAsync();
|
||||
if (this.IsHandshaked)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
if (!this.Online)
|
||||
{
|
||||
await base.ConnectAsync(timeout);
|
||||
}
|
||||
|
||||
var request = new HttpRequest()
|
||||
.SetHost(this.RemoteIPHost.Host);
|
||||
request.Headers.Add(HttpHeaders.Connection, "upgrade");
|
||||
request.Headers.Add(HttpHeaders.Upgrade, DmtpUtility.Dmtp.ToLower());
|
||||
|
||||
request.AsMethod(DmtpUtility.Dmtp);
|
||||
var response = this.RequestContent(request, timeout: timeout, token: token);
|
||||
if (response.StatusCode == 101)
|
||||
{
|
||||
this.SwitchProtocolToDmtp();
|
||||
await this.m_dmtpActor.HandshakeAsync(this.Config.GetValue(DmtpConfigExtension.VerifyTokenProperty),
|
||||
this.Config.GetValue(DmtpConfigExtension.DefaultIdProperty),
|
||||
timeout, this.Config.GetValue(DmtpConfigExtension.MetadataProperty), token);
|
||||
return this;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception(response.StatusMessage);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.m_semaphore.Release();
|
||||
this.m_semaphoreForConnect.Release();
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -41,7 +41,7 @@ namespace ThingsGateway.Foundation.Dmtp
|
||||
/// <summary>
|
||||
/// 连接令箭
|
||||
/// </summary>
|
||||
public string VerifyToken => this.Config.GetValue(DmtpConfigExtension.VerifyTokenProperty);
|
||||
public string VerifyToken => this.Config.GetValue(DmtpConfigExtension.DmtpOptionProperty).VerifyToken;
|
||||
|
||||
#region 字段
|
||||
|
||||
|
@@ -40,14 +40,14 @@ namespace ThingsGateway.Foundation.Dmtp
|
||||
public bool IsHandshaked => this.DmtpActor != null && this.DmtpActor.IsHandshaked;
|
||||
|
||||
/// <summary>
|
||||
/// 验证超时时间,默认为3000ms
|
||||
/// 验证超时时间
|
||||
/// </summary>
|
||||
public int VerifyTimeout => this.Config.GetValue(DmtpConfigExtension.VerifyTimeoutProperty);
|
||||
public TimeSpan VerifyTimeout => this.Config.GetValue(DmtpConfigExtension.DmtpOptionProperty).VerifyTimeout;
|
||||
|
||||
/// <summary>
|
||||
/// 连接令箭
|
||||
/// </summary>
|
||||
public string VerifyToken => this.Config.GetValue(DmtpConfigExtension.VerifyTokenProperty);
|
||||
public string VerifyToken => this.Config.GetValue(DmtpConfigExtension.DmtpOptionProperty).VerifyToken;
|
||||
|
||||
#region 断开
|
||||
|
||||
|
@@ -10,7 +10,6 @@
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
|
||||
namespace ThingsGateway.Foundation.Dmtp
|
||||
{
|
||||
/// <summary>
|
||||
@@ -18,20 +17,5 @@ namespace ThingsGateway.Foundation.Dmtp
|
||||
/// </summary>
|
||||
public interface IHttpDmtpClient : IHttpClient, IHttpDmtpClientBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 建立Tcp,并发送Http请求,最后完成Dmtp握手连接。
|
||||
/// </summary>
|
||||
/// <param name="token"></param>
|
||||
/// <param name="timeout"></param>
|
||||
/// <returns></returns>
|
||||
IHttpDmtpClient Connect(CancellationToken token, int timeout = 5000);
|
||||
|
||||
/// <summary>
|
||||
/// 建立Tcp,并发送Http请求,最后完成Dmtp握手连接。
|
||||
/// </summary>
|
||||
/// <param name="token"></param>
|
||||
/// <param name="timeout"></param>
|
||||
/// <returns></returns>
|
||||
Task<IHttpDmtpClient> ConnectAsync(CancellationToken token, int timeout = 5000);
|
||||
}
|
||||
}
|
@@ -17,20 +17,6 @@ namespace ThingsGateway.Foundation.Dmtp
|
||||
/// </summary>
|
||||
public interface ITcpDmtpClient : ITcpDmtpClientBase, ITcpClient
|
||||
{
|
||||
/// <summary>
|
||||
/// 建立Tcp连接,并且执行握手。
|
||||
/// </summary>
|
||||
/// <param name="token">可取消令箭</param>
|
||||
/// <param name="timeout">超时时间</param>
|
||||
/// <returns></returns>
|
||||
ITcpDmtpClient Connect(CancellationToken token, int timeout = 5000);
|
||||
|
||||
/// <summary>
|
||||
/// 建立Tcp连接,并且执行握手。
|
||||
/// </summary>
|
||||
/// <param name="token">可取消令箭</param>
|
||||
/// <param name="timeout">超时时间</param>
|
||||
/// <returns></returns>
|
||||
Task<ITcpDmtpClient> ConnectAsync(CancellationToken token, int timeout = 5000);
|
||||
}
|
||||
}
|
@@ -46,14 +46,14 @@ namespace ThingsGateway.Foundation.Dmtp
|
||||
|
||||
#region 字段
|
||||
|
||||
private readonly SemaphoreSlim m_semaphore = new SemaphoreSlim(1, 1);
|
||||
private readonly SemaphoreSlim m_semaphoreForConnect = new SemaphoreSlim(1, 1);
|
||||
private bool m_allowRoute;
|
||||
private SealedDmtpActor m_dmtpActor;
|
||||
private Func<string, Task<IDmtpActor>> m_findDmtpActor;
|
||||
|
||||
#endregion 字段
|
||||
|
||||
/// <inheritdoc cref="IDmtpActor.IsHandshaked"/>
|
||||
/// <inheritdoc cref="IHandshakeObject.IsHandshaked"/>
|
||||
public bool IsHandshaked => this.m_dmtpActor != null && this.m_dmtpActor.IsHandshaked;
|
||||
|
||||
#region 断开
|
||||
@@ -95,98 +95,60 @@ namespace ThingsGateway.Foundation.Dmtp
|
||||
#region 连接
|
||||
|
||||
/// <summary>
|
||||
/// 建立Tcp连接,并且执行握手。
|
||||
/// 进行Dmtp协议的握手连接
|
||||
/// </summary>
|
||||
/// <param name="timeout"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
public override ITcpClient Connect(int timeout = 5000)
|
||||
public override void Connect(int timeout, CancellationToken token)
|
||||
{
|
||||
lock (this.SyncRoot)
|
||||
try
|
||||
{
|
||||
this.m_semaphoreForConnect.Wait(token);
|
||||
if (this.IsHandshaked)
|
||||
{
|
||||
return this;
|
||||
return;
|
||||
}
|
||||
if (!this.Online)
|
||||
{
|
||||
base.Connect(timeout);
|
||||
base.Connect(timeout, token);
|
||||
}
|
||||
|
||||
this.m_dmtpActor.Handshake(this.Config.GetValue(DmtpConfigExtension.VerifyTokenProperty),
|
||||
this.Config.GetValue(DmtpConfigExtension.DefaultIdProperty), timeout, this.Config.GetValue(DmtpConfigExtension.MetadataProperty), CancellationToken.None);
|
||||
return this;
|
||||
this.m_dmtpActor.Handshake(this.Config.GetValue(DmtpConfigExtension.DmtpOptionProperty).VerifyToken,
|
||||
this.Config.GetValue(DmtpConfigExtension.DmtpOptionProperty).Id, timeout, this.Config.GetValue(DmtpConfigExtension.DmtpOptionProperty).Metadata, token);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual ITcpDmtpClient Connect(CancellationToken token, int timeout = 5000)
|
||||
{
|
||||
lock (this.SyncRoot)
|
||||
finally
|
||||
{
|
||||
if (this.IsHandshaked)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
if (!this.Online)
|
||||
{
|
||||
base.Connect(timeout);
|
||||
}
|
||||
|
||||
this.m_dmtpActor.Handshake(this.Config.GetValue(DmtpConfigExtension.VerifyTokenProperty),
|
||||
this.Config.GetValue(DmtpConfigExtension.DefaultIdProperty), timeout, this.Config.GetValue(DmtpConfigExtension.MetadataProperty), token);
|
||||
return this;
|
||||
this.m_semaphoreForConnect.Release();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 建立Tcp连接,并且执行握手。
|
||||
/// 异步进行Dmtp协议的握手连接
|
||||
/// </summary>
|
||||
/// <param name="timeout"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
public override async Task<ITcpClient> ConnectAsync(int timeout = 5000)
|
||||
public override async Task ConnectAsync(int timeout, CancellationToken token)
|
||||
{
|
||||
try
|
||||
{
|
||||
await this.m_semaphore.WaitAsync();
|
||||
await this.m_semaphoreForConnect.WaitAsync(timeout, token);
|
||||
if (this.IsHandshaked)
|
||||
{
|
||||
return this;
|
||||
return;
|
||||
}
|
||||
if (!this.Online)
|
||||
{
|
||||
await base.ConnectAsync(timeout).ConfigureFalseAwait();
|
||||
await base.ConnectAsync(timeout, token);
|
||||
}
|
||||
|
||||
await this.m_dmtpActor.HandshakeAsync(this.Config.GetValue(DmtpConfigExtension.VerifyTokenProperty), this.Config.GetValue(DmtpConfigExtension.DefaultIdProperty), timeout, this.Config.GetValue(DmtpConfigExtension.MetadataProperty), CancellationToken.None).ConfigureFalseAwait();
|
||||
return this;
|
||||
await this.m_dmtpActor.HandshakeAsync(this.Config.GetValue(DmtpConfigExtension.DmtpOptionProperty).VerifyToken,
|
||||
this.Config.GetValue(DmtpConfigExtension.DmtpOptionProperty).Id, timeout, this.Config.GetValue(DmtpConfigExtension.DmtpOptionProperty).Metadata, token);
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.m_semaphore.Release();
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual async Task<ITcpDmtpClient> ConnectAsync(CancellationToken token, int timeout = 5000)
|
||||
{
|
||||
try
|
||||
{
|
||||
await this.m_semaphore.WaitAsync();
|
||||
if (this.IsHandshaked)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
if (!this.Online)
|
||||
{
|
||||
await base.ConnectAsync(timeout).ConfigureFalseAwait();
|
||||
}
|
||||
|
||||
await this.m_dmtpActor.HandshakeAsync(this.Config.GetValue(DmtpConfigExtension.VerifyTokenProperty), this.Config.GetValue(DmtpConfigExtension.DefaultIdProperty), timeout, this.Config.GetValue(DmtpConfigExtension.MetadataProperty), token).ConfigureFalseAwait();
|
||||
return this;
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.m_semaphore.Release();
|
||||
this.m_semaphoreForConnect.Release();
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -48,7 +48,7 @@ namespace ThingsGateway.Foundation.Dmtp
|
||||
/// <summary>
|
||||
/// 连接令箭
|
||||
/// </summary>
|
||||
public string VerifyToken => this.Config?.GetValue(DmtpConfigExtension.VerifyTokenProperty);
|
||||
public string VerifyToken => this.Config.GetValue(DmtpConfigExtension.DmtpOptionProperty).VerifyToken;
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void LoadConfig(TouchSocketConfig config)
|
||||
|
@@ -43,18 +43,18 @@ namespace ThingsGateway.Foundation.Dmtp
|
||||
/// <inheritdoc/>
|
||||
public IDmtpActor DmtpActor { get => this.m_dmtpActor; }
|
||||
|
||||
/// <inheritdoc cref="IDmtpActor.IsHandshaked"/>
|
||||
/// <inheritdoc cref="IHandshakeObject.IsHandshaked"/>
|
||||
public bool IsHandshaked => this.DmtpActor != null && this.DmtpActor.IsHandshaked;
|
||||
|
||||
/// <summary>
|
||||
/// 验证超时时间,默认为3000ms
|
||||
/// </summary>
|
||||
public int VerifyTimeout => this.Config.GetValue(DmtpConfigExtension.VerifyTimeoutProperty);
|
||||
public TimeSpan VerifyTimeout => this.Config.GetValue(DmtpConfigExtension.DmtpOptionProperty).VerifyTimeout;
|
||||
|
||||
/// <summary>
|
||||
/// 连接令箭
|
||||
/// </summary>
|
||||
public string VerifyToken => this.Config.GetValue(DmtpConfigExtension.VerifyTokenProperty);
|
||||
public string VerifyToken => this.Config.GetValue(DmtpConfigExtension.DmtpOptionProperty).VerifyToken;
|
||||
|
||||
#region 内部委托绑定
|
||||
|
||||
|
@@ -28,7 +28,7 @@ namespace ThingsGateway.Foundation.Dmtp
|
||||
/// <summary>
|
||||
/// IWebSocketDmtpClient
|
||||
/// </summary>
|
||||
public interface IWebSocketDmtpClient : IWebSocketDmtpClientBase
|
||||
public interface IWebSocketDmtpClient : IWebSocketDmtpClientBase, ISetupConfigObject
|
||||
{
|
||||
/// <summary>
|
||||
/// 异步连接
|
||||
|
@@ -22,14 +22,5 @@ namespace ThingsGateway.Foundation.Dmtp
|
||||
/// </summary>
|
||||
string Id { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 加载到当前客户端的配置
|
||||
/// </summary>
|
||||
TouchSocketConfig Config { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否已完成<see cref="IDmtpActor.IsHandshaked"/>
|
||||
/// </summary>
|
||||
bool IsHandshaked { get; }
|
||||
}
|
||||
}
|
@@ -29,7 +29,7 @@ namespace ThingsGateway.Foundation.Dmtp
|
||||
/// <summary>
|
||||
/// WebSocketDmtpClient
|
||||
/// </summary>
|
||||
public class WebSocketDmtpClient : BaseSocket, IWebSocketDmtpClient
|
||||
public class WebSocketDmtpClient : SetupConfigObject, IWebSocketDmtpClient
|
||||
{
|
||||
/// <summary>
|
||||
/// WebSocketDmtpClient
|
||||
@@ -66,13 +66,7 @@ namespace ThingsGateway.Foundation.Dmtp
|
||||
/// <inheritdoc/>
|
||||
public bool CanSend => this.m_client.State == WebSocketState.Open;
|
||||
|
||||
/// <summary>
|
||||
/// 客户端配置
|
||||
/// </summary>
|
||||
public TouchSocketConfig Config { get; private set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IContainer Container { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 断开连接
|
||||
@@ -94,20 +88,14 @@ namespace ThingsGateway.Foundation.Dmtp
|
||||
/// <inheritdoc/>
|
||||
public DateTime LastSendTime => this.m_sendCounter.LastIncrement;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IPluginsManager PluginsManager { get; private set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Protocol Protocol { get; set; } = DmtpUtility.DmtpProtocol;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int ReceiveBufferSize => this.m_receiveBufferSize;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IPHost RemoteIPHost { get; private set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int SendBufferSize => this.m_sendBufferSize;
|
||||
|
||||
/// <summary>
|
||||
/// 发送<see cref="IDmtpActor"/>关闭消息。
|
||||
@@ -165,9 +153,9 @@ namespace ThingsGateway.Foundation.Dmtp
|
||||
_ = this.BeginReceive();
|
||||
}
|
||||
|
||||
this.m_dmtpActor.Handshake(this.Config.GetValue(DmtpConfigExtension.VerifyTokenProperty),
|
||||
this.Config.GetValue(DmtpConfigExtension.DefaultIdProperty),
|
||||
timeout, this.Config.GetValue(DmtpConfigExtension.MetadataProperty), token);
|
||||
this.m_dmtpActor.Handshake(this.Config.GetValue(DmtpConfigExtension.DmtpOptionProperty).VerifyToken,
|
||||
this.Config.GetValue(DmtpConfigExtension.DmtpOptionProperty).Id,
|
||||
timeout, this.Config.GetValue(DmtpConfigExtension.DmtpOptionProperty).Metadata, token);
|
||||
this.IsHandshaked = true;
|
||||
}
|
||||
finally
|
||||
@@ -194,28 +182,6 @@ namespace ThingsGateway.Foundation.Dmtp
|
||||
this.DmtpActor.ResetId(newId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 配置
|
||||
/// </summary>
|
||||
/// <param name="config"></param>
|
||||
/// <exception cref="Exception"></exception>
|
||||
public IWebSocketDmtpClient Setup(TouchSocketConfig config)
|
||||
{
|
||||
if (config == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(config));
|
||||
}
|
||||
|
||||
this.ThrowIfDisposed();
|
||||
|
||||
this.BuildConfig(config);
|
||||
|
||||
this.PluginsManager.Raise(nameof(ILoadingConfigPlugin.OnLoadingConfig), this, new ConfigEventArgs(config));
|
||||
this.LoadConfig(this.Config);
|
||||
this.PluginsManager.Raise(nameof(ILoadedConfigPlugin.OnLoadedConfig), this, new ConfigEventArgs(config));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Dispose(bool disposing)
|
||||
@@ -236,11 +202,9 @@ namespace ThingsGateway.Foundation.Dmtp
|
||||
/// 加载配置
|
||||
/// </summary>
|
||||
/// <param name="config"></param>
|
||||
protected virtual void LoadConfig(TouchSocketConfig config)
|
||||
protected override void LoadConfig(TouchSocketConfig config)
|
||||
{
|
||||
this.RemoteIPHost = config.GetValue(TouchSocketConfigExtension.RemoteIPHostProperty);
|
||||
this.Logger ??= this.Container.Resolve<ILog>();
|
||||
|
||||
if (this.Container.IsRegistered(typeof(IDmtpRouteService)))
|
||||
{
|
||||
this.m_findDmtpActor = this.Container.Resolve<IDmtpRouteService>().FindDmtpActor;
|
||||
@@ -266,7 +230,7 @@ namespace ThingsGateway.Foundation.Dmtp
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
using (var byteBlock = new ByteBlock(this.ReceiveBufferSize))
|
||||
using (var byteBlock = new ByteBlock(this.m_receiveBufferSize))
|
||||
{
|
||||
var result = await this.m_client.ReceiveAsync(new ArraySegment<byte>(byteBlock.Buffer, 0, byteBlock.Capacity), default);
|
||||
if (result.Count == 0)
|
||||
@@ -290,7 +254,7 @@ namespace ThingsGateway.Foundation.Dmtp
|
||||
|
||||
private void BreakOut(string msg, bool manual)
|
||||
{
|
||||
lock (this.SyncRoot)
|
||||
lock (this.m_semaphoreForConnect)
|
||||
{
|
||||
if (this.IsHandshaked)
|
||||
{
|
||||
@@ -304,47 +268,6 @@ namespace ThingsGateway.Foundation.Dmtp
|
||||
}
|
||||
}
|
||||
|
||||
private void BuildConfig(TouchSocketConfig config)
|
||||
{
|
||||
this.Config = config;
|
||||
|
||||
if (!(config.GetValue(TouchSocketCoreConfigExtension.ContainerProperty) is IContainer container))
|
||||
{
|
||||
container = new Container();
|
||||
}
|
||||
|
||||
if (!container.IsRegistered(typeof(ILog)))
|
||||
{
|
||||
container.RegisterSingleton<ILog, LoggerGroup>();
|
||||
}
|
||||
|
||||
if (!(config.GetValue(TouchSocketCoreConfigExtension.PluginsManagerProperty) is IPluginsManager pluginsManager))
|
||||
{
|
||||
pluginsManager = new PluginsManager(container);
|
||||
}
|
||||
|
||||
if (container.IsRegistered(typeof(IPluginsManager)))
|
||||
{
|
||||
pluginsManager = container.Resolve<IPluginsManager>();
|
||||
}
|
||||
else
|
||||
{
|
||||
container.RegisterSingleton<IPluginsManager>(pluginsManager);
|
||||
}
|
||||
|
||||
if (config.GetValue(TouchSocketCoreConfigExtension.ConfigureContainerProperty) is Action<IContainer> actionContainer)
|
||||
{
|
||||
actionContainer.Invoke(container);
|
||||
}
|
||||
|
||||
if (config.GetValue(TouchSocketCoreConfigExtension.ConfigurePluginsProperty) is Action<IPluginsManager> actionPluginsManager)
|
||||
{
|
||||
pluginsManager.Enable = true;
|
||||
actionPluginsManager.Invoke(pluginsManager);
|
||||
}
|
||||
this.Container = container;
|
||||
this.PluginsManager = pluginsManager;
|
||||
}
|
||||
|
||||
private void OnReceivePeriod(long value)
|
||||
{
|
||||
@@ -366,7 +289,7 @@ namespace ThingsGateway.Foundation.Dmtp
|
||||
var message = (DmtpMessage)requestInfo;
|
||||
if (!this.m_dmtpActor.InputReceivedData(message).GetFalseAwaitResult())
|
||||
{
|
||||
this.PluginsManager.Raise(nameof(IDmtpReceivedPlugin.OnDmtpReceived), this, new DmtpMessageEventArgs(message));
|
||||
this.PluginsManager?.Raise(nameof(IDmtpReceivedPlugin.OnDmtpReceived), this, new DmtpMessageEventArgs(message));
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -10,9 +10,6 @@
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
|
||||
namespace ThingsGateway.Foundation.Dmtp
|
||||
{
|
||||
/// <summary>
|
||||
|
@@ -18,77 +18,20 @@ namespace ThingsGateway.Foundation.Dmtp
|
||||
public static class DmtpConfigExtension
|
||||
{
|
||||
/// <summary>
|
||||
/// 默认使用Id。
|
||||
/// 设置Dmtp相关配置。
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty<string> DefaultIdProperty =
|
||||
DependencyProperty<string>.Register("DefaultId", null);
|
||||
public static readonly DependencyProperty<DmtpOption> DmtpOptionProperty =
|
||||
DependencyProperty<DmtpOption>.Register("DmtpOption", new DmtpOption());
|
||||
|
||||
/// <summary>
|
||||
/// DmtpClient连接时的元数据, 所需类型<see cref="Metadata"/>
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty<Metadata> MetadataProperty = DependencyProperty<Metadata>.Register("Metadata", null);
|
||||
|
||||
/// <summary>
|
||||
/// 验证超时时间,默认为3000ms, 所需类型<see cref="int"/>
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty<int> VerifyTimeoutProperty =
|
||||
DependencyProperty<int>.Register("VerifyTimeout", 3000);
|
||||
|
||||
/// <summary>
|
||||
/// 连接令箭,当为null或空时,重置为默认值“rrqm”, 所需类型<see cref="string"/>
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty<string> VerifyTokenProperty =
|
||||
DependencyProperty<string>.Register("VerifyToken", "rrqm");
|
||||
|
||||
/// <summary>
|
||||
/// 设置默认的使用Id。仅在DmtpRpc组件适用。
|
||||
/// <para>
|
||||
/// 使用该功能时,仅在服务器的Handshaking之后生效。且如果id重复,则会连接失败。
|
||||
/// </para>
|
||||
/// 设置Dmtp相关配置。
|
||||
/// </summary>
|
||||
/// <param name="config"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static TouchSocketConfig SetDefaultId(this TouchSocketConfig config, string value)
|
||||
public static TouchSocketConfig SetDmtpOption(this TouchSocketConfig config, DmtpOption value)
|
||||
{
|
||||
config.SetValue(DefaultIdProperty, value);
|
||||
return config;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置DmtpClient连接时的元数据
|
||||
/// <para>仅适用于DmtpClient系类</para>
|
||||
/// </summary>
|
||||
/// <param name="config"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static TouchSocketConfig SetMetadata(this TouchSocketConfig config, Metadata value)
|
||||
{
|
||||
config.SetValue(MetadataProperty, value);
|
||||
return config;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 验证超时时间,默认为3000ms.
|
||||
/// </summary>
|
||||
/// <param name="config"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static TouchSocketConfig SetVerifyTimeout(this TouchSocketConfig config, int value)
|
||||
{
|
||||
config.SetValue(VerifyTimeoutProperty, value);
|
||||
return config;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 连接令箭,当为null或空时,重置为默认值“rrqm”
|
||||
/// </summary>
|
||||
/// <param name="config"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static TouchSocketConfig SetVerifyToken(this TouchSocketConfig config, string value)
|
||||
{
|
||||
config.SetValue(VerifyTokenProperty, value);
|
||||
config.SetValue(DmtpOptionProperty, value);
|
||||
return config;
|
||||
}
|
||||
|
||||
@@ -183,32 +126,6 @@ namespace ThingsGateway.Foundation.Dmtp
|
||||
|
||||
#endregion 创建HttpDmtp
|
||||
|
||||
//#region 创建UdpTouchRpc
|
||||
|
||||
///// <summary>
|
||||
///// 构建UdpTouchRpc类
|
||||
///// </summary>
|
||||
///// <typeparam name="TClient"></typeparam>
|
||||
///// <param name="config"></param>
|
||||
///// <returns></returns>
|
||||
//public static TClient BuildWithUdpTouchRpc<TClient>(this TouchSocketConfig config) where TClient : IUdpTouchRpc
|
||||
//{
|
||||
// TClient client = Activator.CreateInstance<TClient>();
|
||||
// client.Setup(config);
|
||||
// client.Start();
|
||||
// return client;
|
||||
//}
|
||||
|
||||
///// <summary>
|
||||
///// 构建UdpTouchRpc类客户端
|
||||
///// </summary>
|
||||
///// <param name="config"></param>
|
||||
///// <returns></returns>
|
||||
//public static UdpTouchRpc BuildWithUdpTouchRpc(this TouchSocketConfig config)
|
||||
//{
|
||||
// return BuildWithUdpTouchRpc<UdpTouchRpc>(config);
|
||||
//}
|
||||
|
||||
//#endregion 创建UdpTouchRpc
|
||||
}
|
||||
}
|
@@ -383,6 +383,23 @@ namespace ThingsGateway.Foundation.Dmtp.Rpc
|
||||
return default;
|
||||
}
|
||||
|
||||
private static void CheckWaitDataStatus(WaitDataStatus status)
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
return;
|
||||
case WaitDataStatus.Canceled: throw new OperationCanceledException();
|
||||
case WaitDataStatus.Overtime: throw new TimeoutException();
|
||||
case WaitDataStatus.Disposed:
|
||||
case WaitDataStatus.Default:
|
||||
default:
|
||||
{
|
||||
throw new Exception(TouchSocketCoreResource.UnknownError.GetDescription());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region Rpc
|
||||
|
||||
/// <inheritdoc/>
|
||||
@@ -429,53 +446,33 @@ namespace ThingsGateway.Foundation.Dmtp.Rpc
|
||||
}
|
||||
case FeedbackType.WaitSend:
|
||||
{
|
||||
switch (waitData.Wait(invokeOption.Timeout))
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case WaitDataStatus.Overtime:
|
||||
{
|
||||
throw new TimeoutException("等待结果超时");
|
||||
}
|
||||
}
|
||||
CheckWaitDataStatus(waitData.Wait(invokeOption.Timeout));
|
||||
return returnType.GetDefault();
|
||||
}
|
||||
case FeedbackType.WaitInvoke:
|
||||
{
|
||||
switch (waitData.Wait(invokeOption.Timeout))
|
||||
CheckWaitDataStatus(waitData.Wait(invokeOption.Timeout));
|
||||
var resultContext = (DmtpRpcPackage)waitData.WaitResult;
|
||||
resultContext.ThrowStatus();
|
||||
if (resultContext.IsByRef)
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
try
|
||||
{
|
||||
for (var i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
var resultContext = (DmtpRpcPackage)waitData.WaitResult;
|
||||
resultContext.ThrowStatus();
|
||||
if (resultContext.IsByRef)
|
||||
{
|
||||
try
|
||||
{
|
||||
for (var i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
parameters[i] = this.SerializationSelector.DeserializeParameter(resultContext.SerializationType, resultContext.ParametersBytes[i], types[i]);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new Exception(e.Message);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
parameters = null;
|
||||
}
|
||||
return this.SerializationSelector.DeserializeParameter(resultContext.SerializationType, resultContext.ReturnParameterBytes, returnType);
|
||||
}
|
||||
case WaitDataStatus.Overtime:
|
||||
{
|
||||
throw new TimeoutException("等待结果超时");
|
||||
parameters[i] = this.SerializationSelector.DeserializeParameter(resultContext.SerializationType, resultContext.ParametersBytes[i], types[i]);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new Exception(e.Message);
|
||||
}
|
||||
}
|
||||
return returnType.GetDefault();
|
||||
else
|
||||
{
|
||||
parameters = null;
|
||||
}
|
||||
return this.SerializationSelector.DeserializeParameter(resultContext.SerializationType, resultContext.ReturnParameterBytes, returnType);
|
||||
}
|
||||
default:
|
||||
return returnType.GetDefault();
|
||||
@@ -531,44 +528,24 @@ namespace ThingsGateway.Foundation.Dmtp.Rpc
|
||||
|
||||
case FeedbackType.WaitSend:
|
||||
{
|
||||
switch (waitData.Wait(invokeOption.Timeout))
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case WaitDataStatus.Overtime:
|
||||
{
|
||||
throw new TimeoutException("等待结果超时");
|
||||
}
|
||||
}
|
||||
CheckWaitDataStatus(waitData.Wait(invokeOption.Timeout));
|
||||
break;
|
||||
}
|
||||
case FeedbackType.WaitInvoke:
|
||||
{
|
||||
switch (waitData.Wait(invokeOption.Timeout))
|
||||
CheckWaitDataStatus(waitData.Wait(invokeOption.Timeout));
|
||||
var resultContext = (DmtpRpcPackage)waitData.WaitResult;
|
||||
resultContext.ThrowStatus();
|
||||
if (resultContext.IsByRef)
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
{
|
||||
var resultContext = (DmtpRpcPackage)waitData.WaitResult;
|
||||
resultContext.ThrowStatus();
|
||||
if (resultContext.IsByRef)
|
||||
{
|
||||
for (var i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
parameters[i] = this.SerializationSelector.DeserializeParameter(resultContext.SerializationType, resultContext.ParametersBytes[i], types[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
parameters = null;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WaitDataStatus.Overtime:
|
||||
{
|
||||
throw new TimeoutException("等待结果超时");
|
||||
}
|
||||
for (var i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
parameters[i] = this.SerializationSelector.DeserializeParameter(resultContext.SerializationType, resultContext.ParametersBytes[i], types[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
parameters = null;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -630,33 +607,14 @@ namespace ThingsGateway.Foundation.Dmtp.Rpc
|
||||
|
||||
case FeedbackType.WaitSend:
|
||||
{
|
||||
switch (waitData.Wait(invokeOption.Timeout))
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
break;
|
||||
|
||||
case WaitDataStatus.Overtime:
|
||||
{
|
||||
throw new TimeoutException("等待结果超时");
|
||||
}
|
||||
}
|
||||
CheckWaitDataStatus(waitData.Wait(invokeOption.Timeout));
|
||||
break;
|
||||
}
|
||||
case FeedbackType.WaitInvoke:
|
||||
{
|
||||
switch (waitData.Wait(invokeOption.Timeout))
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
{
|
||||
var resultContext = (DmtpRpcPackage)waitData.WaitResult;
|
||||
resultContext.ThrowStatus();
|
||||
break;
|
||||
}
|
||||
case WaitDataStatus.Overtime:
|
||||
{
|
||||
throw new TimeoutException("等待结果超时");
|
||||
}
|
||||
}
|
||||
CheckWaitDataStatus(waitData.Wait(invokeOption.Timeout));
|
||||
var resultContext = (DmtpRpcPackage)waitData.WaitResult;
|
||||
resultContext.ThrowStatus();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -719,31 +677,15 @@ namespace ThingsGateway.Foundation.Dmtp.Rpc
|
||||
}
|
||||
case FeedbackType.WaitSend:
|
||||
{
|
||||
switch (waitData.Wait(invokeOption.Timeout))
|
||||
{
|
||||
case WaitDataStatus.Overtime:
|
||||
{
|
||||
throw new TimeoutException("等待结果超时");
|
||||
}
|
||||
}
|
||||
CheckWaitDataStatus(waitData.Wait(invokeOption.Timeout));
|
||||
return returnType.GetDefault();
|
||||
}
|
||||
case FeedbackType.WaitInvoke:
|
||||
{
|
||||
switch (waitData.Wait(invokeOption.Timeout))
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
{
|
||||
var resultContext = (DmtpRpcPackage)waitData.WaitResult;
|
||||
resultContext.ThrowStatus();
|
||||
return this.SerializationSelector.DeserializeParameter(resultContext.SerializationType, resultContext.ReturnParameterBytes, returnType);
|
||||
}
|
||||
case WaitDataStatus.Overtime:
|
||||
{
|
||||
throw new TimeoutException("等待结果超时");
|
||||
}
|
||||
}
|
||||
return returnType.GetDefault();
|
||||
CheckWaitDataStatus(waitData.Wait(invokeOption.Timeout));
|
||||
var resultContext = (DmtpRpcPackage)waitData.WaitResult;
|
||||
resultContext.ThrowStatus();
|
||||
return this.SerializationSelector.DeserializeParameter(resultContext.SerializationType, resultContext.ReturnParameterBytes, returnType);
|
||||
}
|
||||
|
||||
default:
|
||||
@@ -794,7 +736,7 @@ namespace ThingsGateway.Foundation.Dmtp.Rpc
|
||||
}
|
||||
|
||||
rpcPackage.Package(byteBlock);
|
||||
this.DmtpActor.Send(this.m_invoke_Request, byteBlock.Buffer, 0, byteBlock.Len);
|
||||
await this.DmtpActor.SendAsync(this.m_invoke_Request, byteBlock.Buffer, 0, byteBlock.Len);
|
||||
}
|
||||
|
||||
switch (invokeOption.FeedbackType)
|
||||
@@ -804,33 +746,14 @@ namespace ThingsGateway.Foundation.Dmtp.Rpc
|
||||
|
||||
case FeedbackType.WaitSend:
|
||||
{
|
||||
switch (await waitData.WaitAsync(invokeOption.Timeout).ConfigureFalseAwait())
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
break;
|
||||
|
||||
case WaitDataStatus.Overtime:
|
||||
{
|
||||
throw new TimeoutException("等待结果超时");
|
||||
}
|
||||
}
|
||||
CheckWaitDataStatus(await waitData.WaitAsync(invokeOption.Timeout).ConfigureFalseAwait());
|
||||
break;
|
||||
}
|
||||
case FeedbackType.WaitInvoke:
|
||||
{
|
||||
switch (await waitData.WaitAsync(invokeOption.Timeout).ConfigureFalseAwait())
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
{
|
||||
var resultContext = (DmtpRpcPackage)waitData.WaitResult;
|
||||
resultContext.ThrowStatus();
|
||||
break;
|
||||
}
|
||||
case WaitDataStatus.Overtime:
|
||||
{
|
||||
throw new TimeoutException("等待结果超时");
|
||||
}
|
||||
}
|
||||
CheckWaitDataStatus(await waitData.WaitAsync(invokeOption.Timeout).ConfigureFalseAwait());
|
||||
var resultContext = (DmtpRpcPackage)waitData.WaitResult;
|
||||
resultContext.ThrowStatus();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -881,7 +804,7 @@ namespace ThingsGateway.Foundation.Dmtp.Rpc
|
||||
|
||||
rpcPackage.Package(byteBlock);
|
||||
|
||||
this.DmtpActor.Send(this.m_invoke_Request, byteBlock.Buffer, 0, byteBlock.Len);
|
||||
await this.DmtpActor.SendAsync(this.m_invoke_Request, byteBlock.Buffer, 0, byteBlock.Len);
|
||||
}
|
||||
|
||||
switch (invokeOption.FeedbackType)
|
||||
@@ -892,31 +815,15 @@ namespace ThingsGateway.Foundation.Dmtp.Rpc
|
||||
}
|
||||
case FeedbackType.WaitSend:
|
||||
{
|
||||
switch (await waitData.WaitAsync(invokeOption.Timeout).ConfigureFalseAwait())
|
||||
{
|
||||
case WaitDataStatus.Overtime:
|
||||
{
|
||||
throw new TimeoutException("等待结果超时");
|
||||
}
|
||||
}
|
||||
CheckWaitDataStatus(await waitData.WaitAsync(invokeOption.Timeout).ConfigureFalseAwait());
|
||||
return returnType.GetDefault();
|
||||
}
|
||||
case FeedbackType.WaitInvoke:
|
||||
{
|
||||
switch (await waitData.WaitAsync(invokeOption.Timeout).ConfigureFalseAwait())
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
{
|
||||
var resultContext = (DmtpRpcPackage)waitData.WaitResult;
|
||||
resultContext.ThrowStatus();
|
||||
return this.SerializationSelector.DeserializeParameter(resultContext.SerializationType, resultContext.ReturnParameterBytes, returnType);
|
||||
}
|
||||
case WaitDataStatus.Overtime:
|
||||
{
|
||||
throw new TimeoutException("等待结果超时");
|
||||
}
|
||||
}
|
||||
return returnType.GetDefault();
|
||||
CheckWaitDataStatus(await waitData.WaitAsync(invokeOption.Timeout).ConfigureFalseAwait());
|
||||
var resultContext = (DmtpRpcPackage)waitData.WaitResult;
|
||||
resultContext.ThrowStatus();
|
||||
return this.SerializationSelector.DeserializeParameter(resultContext.SerializationType, resultContext.ReturnParameterBytes, returnType);
|
||||
}
|
||||
|
||||
default:
|
||||
@@ -1000,33 +907,14 @@ namespace ThingsGateway.Foundation.Dmtp.Rpc
|
||||
|
||||
case FeedbackType.WaitSend:
|
||||
{
|
||||
switch (waitData.Wait(invokeOption.Timeout))
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
break;
|
||||
|
||||
case WaitDataStatus.Overtime:
|
||||
{
|
||||
throw new TimeoutException("等待结果超时");
|
||||
}
|
||||
}
|
||||
CheckWaitDataStatus(waitData.Wait(invokeOption.Timeout));
|
||||
break;
|
||||
}
|
||||
case FeedbackType.WaitInvoke:
|
||||
{
|
||||
switch (waitData.Wait(invokeOption.Timeout))
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
{
|
||||
var resultContext = (DmtpRpcPackage)waitData.WaitResult;
|
||||
resultContext.ThrowStatus();
|
||||
break;
|
||||
}
|
||||
case WaitDataStatus.Overtime:
|
||||
{
|
||||
throw new TimeoutException("等待结果超时");
|
||||
}
|
||||
}
|
||||
CheckWaitDataStatus(waitData.Wait(invokeOption.Timeout));
|
||||
var resultContext = (DmtpRpcPackage)waitData.WaitResult;
|
||||
resultContext.ThrowStatus();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -1105,31 +993,15 @@ namespace ThingsGateway.Foundation.Dmtp.Rpc
|
||||
}
|
||||
case FeedbackType.WaitSend:
|
||||
{
|
||||
switch (waitData.Wait(invokeOption.Timeout))
|
||||
{
|
||||
case WaitDataStatus.Overtime:
|
||||
{
|
||||
throw new TimeoutException("等待结果超时");
|
||||
}
|
||||
}
|
||||
CheckWaitDataStatus(waitData.Wait(invokeOption.Timeout));
|
||||
return returnType.GetDefault();
|
||||
}
|
||||
case FeedbackType.WaitInvoke:
|
||||
{
|
||||
switch (waitData.Wait(invokeOption.Timeout))
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
{
|
||||
var resultContext = (DmtpRpcPackage)waitData.WaitResult;
|
||||
resultContext.ThrowStatus();
|
||||
return this.SerializationSelector.DeserializeParameter(resultContext.SerializationType, resultContext.ReturnParameterBytes, returnType);
|
||||
}
|
||||
case WaitDataStatus.Overtime:
|
||||
{
|
||||
throw new TimeoutException("等待结果超时");
|
||||
}
|
||||
}
|
||||
return returnType.GetDefault();
|
||||
CheckWaitDataStatus(waitData.Wait(invokeOption.Timeout));
|
||||
var resultContext = (DmtpRpcPackage)waitData.WaitResult;
|
||||
resultContext.ThrowStatus();
|
||||
return this.SerializationSelector.DeserializeParameter(resultContext.SerializationType, resultContext.ReturnParameterBytes, returnType);
|
||||
}
|
||||
|
||||
default:
|
||||
@@ -1206,40 +1078,24 @@ namespace ThingsGateway.Foundation.Dmtp.Rpc
|
||||
}
|
||||
case FeedbackType.WaitSend:
|
||||
{
|
||||
switch (waitData.Wait(invokeOption.Timeout))
|
||||
{
|
||||
case WaitDataStatus.Overtime:
|
||||
{
|
||||
throw new TimeoutException("等待结果超时");
|
||||
}
|
||||
}
|
||||
CheckWaitDataStatus(waitData.Wait(invokeOption.Timeout));
|
||||
return;
|
||||
}
|
||||
case FeedbackType.WaitInvoke:
|
||||
{
|
||||
switch (waitData.Wait(invokeOption.Timeout))
|
||||
CheckWaitDataStatus(waitData.Wait(invokeOption.Timeout));
|
||||
var resultContext = (DmtpRpcPackage)waitData.WaitResult;
|
||||
resultContext.ThrowStatus();
|
||||
if (resultContext.IsByRef)
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
{
|
||||
var resultContext = (DmtpRpcPackage)waitData.WaitResult;
|
||||
resultContext.ThrowStatus();
|
||||
if (resultContext.IsByRef)
|
||||
{
|
||||
for (var i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
parameters[i] = this.SerializationSelector.DeserializeParameter(resultContext.SerializationType, resultContext.ParametersBytes[i], types[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
parameters = null;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WaitDataStatus.Overtime:
|
||||
{
|
||||
throw new TimeoutException("等待结果超时");
|
||||
}
|
||||
for (var i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
parameters[i] = this.SerializationSelector.DeserializeParameter(resultContext.SerializationType, resultContext.ParametersBytes[i], types[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
parameters = null;
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -1315,42 +1171,26 @@ namespace ThingsGateway.Foundation.Dmtp.Rpc
|
||||
}
|
||||
case FeedbackType.WaitSend:
|
||||
{
|
||||
switch (waitData.Wait(invokeOption.Timeout))
|
||||
{
|
||||
case WaitDataStatus.Overtime:
|
||||
{
|
||||
throw new TimeoutException("等待结果超时");
|
||||
}
|
||||
}
|
||||
CheckWaitDataStatus(waitData.Wait(invokeOption.Timeout));
|
||||
return returnType.GetDefault();
|
||||
}
|
||||
case FeedbackType.WaitInvoke:
|
||||
{
|
||||
switch (waitData.Wait(invokeOption.Timeout))
|
||||
CheckWaitDataStatus(waitData.Wait(invokeOption.Timeout));
|
||||
var resultContext = (DmtpRpcPackage)waitData.WaitResult;
|
||||
resultContext.ThrowStatus();
|
||||
if (resultContext.IsByRef)
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
{
|
||||
var resultContext = (DmtpRpcPackage)waitData.WaitResult;
|
||||
resultContext.ThrowStatus();
|
||||
if (resultContext.IsByRef)
|
||||
{
|
||||
for (var i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
parameters[i] = this.SerializationSelector.DeserializeParameter(resultContext.SerializationType, resultContext.ParametersBytes[i], types[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
parameters = null;
|
||||
}
|
||||
return this.SerializationSelector.DeserializeParameter(resultContext.SerializationType, resultContext.ReturnParameterBytes, returnType);
|
||||
}
|
||||
case WaitDataStatus.Overtime:
|
||||
{
|
||||
throw new TimeoutException("等待结果超时");
|
||||
}
|
||||
for (var i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
parameters[i] = this.SerializationSelector.DeserializeParameter(resultContext.SerializationType, resultContext.ParametersBytes[i], types[i]);
|
||||
}
|
||||
}
|
||||
return returnType.GetDefault();
|
||||
else
|
||||
{
|
||||
parameters = null;
|
||||
}
|
||||
return this.SerializationSelector.DeserializeParameter(resultContext.SerializationType, resultContext.ReturnParameterBytes, returnType);
|
||||
}
|
||||
|
||||
default:
|
||||
@@ -1420,7 +1260,7 @@ namespace ThingsGateway.Foundation.Dmtp.Rpc
|
||||
|
||||
rpcPackage.Package(byteBlock);
|
||||
|
||||
this.DmtpActor.Send(this.m_invoke_Request, byteBlock.Buffer, 0, byteBlock.Len);
|
||||
await this.DmtpActor.SendAsync(this.m_invoke_Request, byteBlock.Buffer, 0, byteBlock.Len);
|
||||
}
|
||||
|
||||
switch (invokeOption.FeedbackType)
|
||||
@@ -1430,33 +1270,14 @@ namespace ThingsGateway.Foundation.Dmtp.Rpc
|
||||
|
||||
case FeedbackType.WaitSend:
|
||||
{
|
||||
switch (await waitData.WaitAsync(invokeOption.Timeout).ConfigureFalseAwait())
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
break;
|
||||
|
||||
case WaitDataStatus.Overtime:
|
||||
{
|
||||
throw new TimeoutException("等待结果超时");
|
||||
}
|
||||
}
|
||||
CheckWaitDataStatus(await waitData.WaitAsync(invokeOption.Timeout).ConfigureFalseAwait());
|
||||
break;
|
||||
}
|
||||
case FeedbackType.WaitInvoke:
|
||||
{
|
||||
switch (await waitData.WaitAsync(invokeOption.Timeout).ConfigureFalseAwait())
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
{
|
||||
var resultContext = (DmtpRpcPackage)waitData.WaitResult;
|
||||
resultContext.ThrowStatus();
|
||||
break;
|
||||
}
|
||||
case WaitDataStatus.Overtime:
|
||||
{
|
||||
throw new TimeoutException("等待结果超时");
|
||||
}
|
||||
}
|
||||
CheckWaitDataStatus(await waitData.WaitAsync(invokeOption.Timeout).ConfigureFalseAwait());
|
||||
var resultContext = (DmtpRpcPackage)waitData.WaitResult;
|
||||
resultContext.ThrowStatus();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -1524,7 +1345,7 @@ namespace ThingsGateway.Foundation.Dmtp.Rpc
|
||||
|
||||
rpcPackage.Package(byteBlock);
|
||||
|
||||
this.DmtpActor.Send(this.m_invoke_Request, byteBlock.Buffer, 0, byteBlock.Len);
|
||||
await this.DmtpActor.SendAsync(this.m_invoke_Request, byteBlock.Buffer, 0, byteBlock.Len);
|
||||
}
|
||||
|
||||
switch (invokeOption.FeedbackType)
|
||||
@@ -1535,31 +1356,15 @@ namespace ThingsGateway.Foundation.Dmtp.Rpc
|
||||
}
|
||||
case FeedbackType.WaitSend:
|
||||
{
|
||||
switch (await waitData.WaitAsync(invokeOption.Timeout).ConfigureFalseAwait())
|
||||
{
|
||||
case WaitDataStatus.Overtime:
|
||||
{
|
||||
throw new TimeoutException("等待结果超时");
|
||||
}
|
||||
}
|
||||
CheckWaitDataStatus(await waitData.WaitAsync(invokeOption.Timeout).ConfigureFalseAwait());
|
||||
return returnType.GetDefault();
|
||||
}
|
||||
case FeedbackType.WaitInvoke:
|
||||
{
|
||||
switch (await waitData.WaitAsync(invokeOption.Timeout).ConfigureFalseAwait())
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
{
|
||||
var resultContext = (DmtpRpcPackage)waitData.WaitResult;
|
||||
resultContext.ThrowStatus();
|
||||
return this.SerializationSelector.DeserializeParameter(resultContext.SerializationType, resultContext.ReturnParameterBytes, returnType);
|
||||
}
|
||||
case WaitDataStatus.Overtime:
|
||||
{
|
||||
throw new TimeoutException("等待结果超时");
|
||||
}
|
||||
}
|
||||
return returnType.GetDefault();
|
||||
CheckWaitDataStatus(await waitData.WaitAsync(invokeOption.Timeout).ConfigureFalseAwait());
|
||||
var resultContext = (DmtpRpcPackage)waitData.WaitResult;
|
||||
resultContext.ThrowStatus();
|
||||
return this.SerializationSelector.DeserializeParameter(resultContext.SerializationType, resultContext.ReturnParameterBytes, returnType);
|
||||
}
|
||||
|
||||
default:
|
||||
|
@@ -22,6 +22,7 @@
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System.Text;
|
||||
using System.Web;
|
||||
|
||||
|
@@ -134,12 +134,12 @@ namespace ThingsGateway.Foundation.Http
|
||||
/// <summary>
|
||||
/// 相对路径(不含参数)
|
||||
/// </summary>
|
||||
public string RelativeURL { get; private set; }
|
||||
public string RelativeURL { get; private set; } = "/";
|
||||
|
||||
/// <summary>
|
||||
/// Url全地址,包含参数
|
||||
/// </summary>
|
||||
public string URL { get; private set; }
|
||||
public string URL { get; private set; } = "/";
|
||||
|
||||
/// <summary>
|
||||
/// 构建响应数据。
|
||||
@@ -175,28 +175,26 @@ namespace ThingsGateway.Foundation.Http
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置Url,必须以“/”开头,可带参数
|
||||
/// 设置Url,可带参数
|
||||
/// </summary>
|
||||
/// <param name="url"></param>
|
||||
/// <param name="justValue"></param>
|
||||
/// <returns></returns>
|
||||
public HttpRequest SetUrl(string url, bool justValue = false)
|
||||
public HttpRequest SetUrl(string url)
|
||||
{
|
||||
this.URL = justValue || url.StartsWith("/") ? url : "/" + url;
|
||||
this.URL = url.StartsWith("/") ? url : $"/{url}";
|
||||
this.ParseUrl();
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 输出
|
||||
/// 设置代理Host
|
||||
/// </summary>
|
||||
public override string ToString()
|
||||
/// <param name="host"></param>
|
||||
/// <returns></returns>
|
||||
public HttpRequest SetProxyHost(string host)
|
||||
{
|
||||
using (var byteBlock = new ByteBlock())
|
||||
{
|
||||
this.Build(byteBlock);
|
||||
return byteBlock.ToString();
|
||||
}
|
||||
this.URL = host;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -412,7 +410,17 @@ namespace ThingsGateway.Foundation.Http
|
||||
}
|
||||
if (urls.Length > 1)
|
||||
{
|
||||
this.m_query = GetParameters(urls[1]);
|
||||
if (this.m_query == null)
|
||||
{
|
||||
this.m_query = GetParameters(urls[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var item in GetParameters(urls[1]))
|
||||
{
|
||||
this.m_query.Add(item.Key, item.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -420,5 +428,17 @@ namespace ThingsGateway.Foundation.Http
|
||||
this.RelativeURL = this.URL;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 输出
|
||||
/// </summary>
|
||||
public override string ToString()
|
||||
{
|
||||
using (var byteBlock = new ByteBlock())
|
||||
{
|
||||
this.Build(byteBlock);
|
||||
return byteBlock.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -196,6 +196,18 @@ namespace ThingsGateway.Foundation.Http
|
||||
this.Responsed = responsed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 输出
|
||||
/// </summary>
|
||||
public override string ToString()
|
||||
{
|
||||
using (var byteBlock = new ByteBlock())
|
||||
{
|
||||
this.Build(byteBlock, false);
|
||||
return byteBlock.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 构建数据为字节数组。
|
||||
/// </summary>
|
||||
|
@@ -38,24 +38,17 @@ namespace ThingsGateway.Foundation.Http
|
||||
/// </summary>
|
||||
public class HttpClientBase : TcpClientBase, IHttpClient
|
||||
{
|
||||
private readonly object m_requestLocker = new object();
|
||||
private readonly WaitData<HttpResponse> m_waitData;
|
||||
#region 字段
|
||||
|
||||
private readonly SemaphoreSlim m_semaphoreForRequest = new SemaphoreSlim(1, 1);
|
||||
private readonly WaitData<HttpResponse> m_waitData = new WaitData<HttpResponse>();
|
||||
private readonly WaitDataAsync<HttpResponse> m_waitDataAsync = new WaitDataAsync<HttpResponse>();
|
||||
private bool m_getContent;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
public HttpClientBase()
|
||||
{
|
||||
this.m_waitData = new WaitData<HttpResponse>();
|
||||
}
|
||||
#endregion 字段
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
/// <param name="timeout"></param>
|
||||
/// <returns></returns>
|
||||
public override ITcpClient Connect(int timeout = 5000)
|
||||
public override void Connect(int timeout, CancellationToken token)
|
||||
{
|
||||
if (this.Config.GetValue(HttpConfigExtensions.HttpProxyProperty) is HttpProxy httpProxy)
|
||||
{
|
||||
@@ -65,13 +58,13 @@ namespace ThingsGateway.Foundation.Http
|
||||
try
|
||||
{
|
||||
this.Config.SetRemoteIPHost(proxyHost);
|
||||
base.Connect(timeout);
|
||||
base.Connect(timeout, token);
|
||||
var request = new HttpRequest();
|
||||
request.InitHeaders()
|
||||
.SetHost(remoteHost.Host)
|
||||
.SetUrl(remoteHost.Host, true)
|
||||
.SetProxyHost(remoteHost.Host)
|
||||
.AsMethod("CONNECT");
|
||||
var response = this.Request(request, timeout: timeout);
|
||||
var response = this.Request(request, false, timeout, token);
|
||||
if (response.IsProxyAuthenticationRequired)
|
||||
{
|
||||
if (credential is null)
|
||||
@@ -90,10 +83,10 @@ namespace ThingsGateway.Foundation.Http
|
||||
if (!response.KeepAlive)
|
||||
{
|
||||
base.Close("代理要求关闭连接,随后重写连接。");
|
||||
base.Connect(timeout);
|
||||
base.Connect(timeout, token);
|
||||
}
|
||||
|
||||
response = this.Request(request, timeout: timeout);
|
||||
response = this.Request(request, false, timeout, token);
|
||||
}
|
||||
|
||||
if (response.StatusCode != 200)
|
||||
@@ -108,37 +101,85 @@ namespace ThingsGateway.Foundation.Http
|
||||
}
|
||||
else
|
||||
{
|
||||
base.Connect(timeout);
|
||||
base.Connect(timeout, token);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override async Task ConnectAsync(int timeout, CancellationToken token)
|
||||
{
|
||||
if (this.Config.GetValue(HttpConfigExtensions.HttpProxyProperty) is HttpProxy httpProxy)
|
||||
{
|
||||
var proxyHost = httpProxy.Host;
|
||||
var credential = httpProxy.Credential;
|
||||
var remoteHost = this.Config.GetValue(TouchSocketConfigExtension.RemoteIPHostProperty);
|
||||
try
|
||||
{
|
||||
this.Config.SetRemoteIPHost(proxyHost);
|
||||
await base.ConnectAsync(timeout, token);
|
||||
var request = new HttpRequest();
|
||||
request.InitHeaders()
|
||||
.SetHost(remoteHost.Host)
|
||||
.SetProxyHost(remoteHost.Host)
|
||||
.AsMethod("CONNECT");
|
||||
var response = await this.RequestAsync(request, false, timeout, token);
|
||||
if (response.IsProxyAuthenticationRequired)
|
||||
{
|
||||
if (credential is null)
|
||||
{
|
||||
throw new Exception("未指定代理的凭据。");
|
||||
}
|
||||
var authHeader = response.Headers.Get(HttpHeaders.ProxyAuthenticate);
|
||||
if (authHeader.IsNullOrEmpty())
|
||||
{
|
||||
throw new Exception("未指定代理身份验证质询。");
|
||||
}
|
||||
|
||||
var ares = new AuthenticationChallenge(authHeader, credential);
|
||||
|
||||
request.Headers.Add(HttpHeaders.ProxyAuthorization, ares.ToString());
|
||||
if (!response.KeepAlive)
|
||||
{
|
||||
base.Close("代理要求关闭连接,随后重写连接。");
|
||||
await base.ConnectAsync(timeout, token);
|
||||
}
|
||||
|
||||
response = await this.RequestAsync(request, timeout: timeout);
|
||||
}
|
||||
|
||||
if (response.StatusCode != 200)
|
||||
{
|
||||
throw new Exception(response.StatusMessage);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.Config.SetRemoteIPHost(remoteHost);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
await base.ConnectAsync(timeout, token);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
/// <param name="request"><inheritdoc/></param>
|
||||
/// <param name="onlyRequest"><inheritdoc/></param>
|
||||
/// <param name="timeout"><inheritdoc/></param>
|
||||
/// <param name="token"><inheritdoc/></param>
|
||||
/// <returns></returns>
|
||||
public HttpResponse Request(HttpRequest request, bool onlyRequest = false, int timeout = 10 * 1000, CancellationToken token = default)
|
||||
{
|
||||
lock (this.m_requestLocker)
|
||||
try
|
||||
{
|
||||
this.m_semaphoreForRequest.Wait(token);
|
||||
this.m_getContent = false;
|
||||
using (var byteBlock = new ByteBlock())
|
||||
{
|
||||
request.Build(byteBlock);
|
||||
|
||||
this.m_waitData.Reset();
|
||||
this.m_waitData.SetCancellationToken(token);
|
||||
|
||||
this.Reset(token);
|
||||
this.DefaultSend(byteBlock);
|
||||
if (onlyRequest)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
switch (this.m_waitData.Wait(timeout))
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
@@ -147,8 +188,7 @@ namespace ThingsGateway.Foundation.Http
|
||||
case WaitDataStatus.Overtime:
|
||||
throw new TimeoutException(TouchSocketHttpResource.Overtime.GetDescription());
|
||||
case WaitDataStatus.Canceled:
|
||||
return default;
|
||||
|
||||
throw new OperationCanceledException();
|
||||
case WaitDataStatus.Default:
|
||||
case WaitDataStatus.Disposed:
|
||||
default:
|
||||
@@ -156,27 +196,62 @@ namespace ThingsGateway.Foundation.Http
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.m_semaphoreForRequest.Release();
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<HttpResponse> RequestAsync(HttpRequest request, bool onlyRequest = false, int timeout = 10 * 1000, CancellationToken token = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
await this.m_semaphoreForRequest.WaitAsync(timeout, token);
|
||||
this.m_getContent = false;
|
||||
using (var byteBlock = new ByteBlock())
|
||||
{
|
||||
request.Build(byteBlock);
|
||||
|
||||
this.Reset(token);
|
||||
await this.DefaultSendAsync(byteBlock);
|
||||
if (onlyRequest)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
switch (await this.m_waitDataAsync.WaitAsync(timeout))
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
return this.m_waitDataAsync.WaitResult;
|
||||
case WaitDataStatus.Overtime:
|
||||
throw new TimeoutException(TouchSocketHttpResource.Overtime.GetDescription());
|
||||
case WaitDataStatus.Canceled:
|
||||
throw new OperationCanceledException();
|
||||
case WaitDataStatus.Default:
|
||||
case WaitDataStatus.Disposed:
|
||||
default:
|
||||
throw new Exception(TouchSocketHttpResource.UnknownError.GetDescription());
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.m_semaphoreForRequest.Release();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <param name="onlyRequest"></param>
|
||||
/// <param name="timeout"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
public HttpResponse RequestContent(HttpRequest request, bool onlyRequest = false, int timeout = 10 * 1000, CancellationToken token = default)
|
||||
{
|
||||
lock (this.m_requestLocker)
|
||||
try
|
||||
{
|
||||
this.m_semaphoreForRequest.Wait(token);
|
||||
this.m_getContent = true;
|
||||
using (var byteBlock = new ByteBlock())
|
||||
{
|
||||
request.Build(byteBlock);
|
||||
|
||||
this.m_waitData.Reset();
|
||||
this.m_waitData.SetCancellationToken(token);
|
||||
this.Reset(token);
|
||||
|
||||
this.DefaultSend(byteBlock);
|
||||
if (onlyRequest)
|
||||
@@ -188,12 +263,10 @@ namespace ThingsGateway.Foundation.Http
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
return this.m_waitData.WaitResult;
|
||||
|
||||
case WaitDataStatus.Overtime:
|
||||
throw new TimeoutException(TouchSocketHttpResource.Overtime.GetDescription());
|
||||
case WaitDataStatus.Canceled:
|
||||
return default;
|
||||
|
||||
throw new OperationCanceledException();
|
||||
case WaitDataStatus.Default:
|
||||
case WaitDataStatus.Disposed:
|
||||
default:
|
||||
@@ -201,6 +274,50 @@ namespace ThingsGateway.Foundation.Http
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.m_semaphoreForRequest.Release();
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<HttpResponse> RequestContentAsync(HttpRequest request, bool onlyRequest = false, int timeout = 10 * 1000, CancellationToken token = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
await this.m_semaphoreForRequest.WaitAsync(timeout, token);
|
||||
this.m_getContent = true;
|
||||
using (var byteBlock = new ByteBlock())
|
||||
{
|
||||
request.Build(byteBlock);
|
||||
|
||||
this.Reset(token);
|
||||
|
||||
await this.DefaultSendAsync(byteBlock);
|
||||
if (onlyRequest)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
switch (await this.m_waitDataAsync.WaitAsync(timeout))
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
return this.m_waitData.WaitResult;
|
||||
case WaitDataStatus.Overtime:
|
||||
throw new TimeoutException(TouchSocketHttpResource.Overtime.GetDescription());
|
||||
case WaitDataStatus.Canceled:
|
||||
throw new OperationCanceledException();
|
||||
case WaitDataStatus.Default:
|
||||
case WaitDataStatus.Disposed:
|
||||
default:
|
||||
throw new Exception(TouchSocketHttpResource.UnknownError.GetDescription());
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.m_semaphoreForRequest.Release();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -213,22 +330,6 @@ namespace ThingsGateway.Foundation.Http
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override Task ReceivedData(ReceivedDataEventArgs e)
|
||||
{
|
||||
if (e.RequestInfo is HttpResponse response)
|
||||
{
|
||||
if (this.m_getContent)
|
||||
{
|
||||
response.TryGetContent(out _);
|
||||
}
|
||||
this.m_waitData.Set(response);
|
||||
}
|
||||
|
||||
return base.ReceivedData(e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
@@ -239,5 +340,42 @@ namespace ThingsGateway.Foundation.Http
|
||||
this.SetDataHandlingAdapter(new HttpClientDataHandlingAdapter());
|
||||
await base.OnConnecting(e);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override async Task OnDisconnected(DisconnectEventArgs e)
|
||||
{
|
||||
this.m_waitData.Cancel();
|
||||
this.m_waitDataAsync.Cancel();
|
||||
await base.OnDisconnected(e);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override Task ReceivedData(ReceivedDataEventArgs e)
|
||||
{
|
||||
if (e.RequestInfo is HttpResponse response)
|
||||
{
|
||||
if (this.m_getContent)
|
||||
{
|
||||
response.TryGetContent(out _);
|
||||
}
|
||||
this.Set(response);
|
||||
}
|
||||
|
||||
return base.ReceivedData(e);
|
||||
}
|
||||
|
||||
private void Reset(CancellationToken token)
|
||||
{
|
||||
this.m_waitData.Reset();
|
||||
this.m_waitDataAsync.Reset();
|
||||
this.m_waitData.SetCancellationToken(token);
|
||||
this.m_waitDataAsync.SetCancellationToken(token);
|
||||
}
|
||||
|
||||
private void Set(HttpResponse response)
|
||||
{
|
||||
this.m_waitData.Set(response);
|
||||
this.m_waitDataAsync.Set(response);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,153 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace ThingsGateway.Foundation.Http
|
||||
{
|
||||
/// <summary>
|
||||
/// HttpClient客户端连接池
|
||||
/// </summary>
|
||||
public class HttpClientPool : SetupConfigObject
|
||||
{
|
||||
private readonly ConcurrentStack<HttpClient> m_httpClients = new ConcurrentStack<HttpClient>();
|
||||
|
||||
/// <summary>
|
||||
/// 最大连接数量。
|
||||
/// </summary>
|
||||
public int MaxCount { get; set; } = 10;
|
||||
|
||||
/// <summary>
|
||||
/// 目标地址
|
||||
/// </summary>
|
||||
public IPHost RemoteIPHost { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 清除现有的所有链接
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
while (this.m_httpClients.TryPop(out var client))
|
||||
{
|
||||
client.SafeDispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发起请求,并获取数据体
|
||||
/// </summary>
|
||||
/// <param name="request">请求体</param>
|
||||
/// <param name="timeout">等待超时时间</param>
|
||||
/// <param name="token">结束等待令箭</param>
|
||||
/// <returns></returns>
|
||||
public HttpResponse RequestContent(HttpRequest request, int timeout = 10 * 1000, CancellationToken token = default)
|
||||
{
|
||||
var client = this.GetHttpClient();
|
||||
try
|
||||
{
|
||||
return client.RequestContent(request, false, timeout, token);
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.ReturnHttpClient(client);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发起请求,并获取数据体
|
||||
/// </summary>
|
||||
/// <param name="request">请求体</param>
|
||||
/// <param name="timeout">等待超时时间</param>
|
||||
/// <param name="token">结束等待令箭</param>
|
||||
/// <returns></returns>
|
||||
public async Task<HttpResponse> RequestContentAsync(HttpRequest request, int timeout = 10000, CancellationToken token = default)
|
||||
{
|
||||
var client = await this.GetHttpClientAsync();
|
||||
try
|
||||
{
|
||||
return await client.RequestContentAsync(request, false, timeout, token);
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.ReturnHttpClient(client);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
this.Clear();
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void LoadConfig(TouchSocketConfig config)
|
||||
{
|
||||
this.RemoteIPHost = config.GetValue(TouchSocketConfigExtension.RemoteIPHostProperty) ?? throw new ArgumentNullException(nameof(this.RemoteIPHost));
|
||||
base.LoadConfig(config);
|
||||
}
|
||||
|
||||
private HttpClient GetHttpClient()
|
||||
{
|
||||
this.ThrowIfDisposed();
|
||||
HttpClient client;
|
||||
while (this.m_httpClients.TryPop(out client))
|
||||
{
|
||||
if (client.Online)
|
||||
{
|
||||
return client;
|
||||
}
|
||||
else
|
||||
{
|
||||
client.SafeDispose();
|
||||
}
|
||||
}
|
||||
|
||||
client = new HttpClient();
|
||||
client.Setup(this.Config.Clone());
|
||||
client.Connect();
|
||||
return client;
|
||||
}
|
||||
|
||||
private async Task<HttpClient> GetHttpClientAsync()
|
||||
{
|
||||
this.ThrowIfDisposed();
|
||||
HttpClient client;
|
||||
while (this.m_httpClients.TryPop(out client))
|
||||
{
|
||||
if (client.Online)
|
||||
{
|
||||
return client;
|
||||
}
|
||||
else
|
||||
{
|
||||
client.SafeDispose();
|
||||
}
|
||||
}
|
||||
|
||||
client = new HttpClient();
|
||||
client.Setup(this.Config.Clone());
|
||||
await client.ConnectAsync();
|
||||
return client;
|
||||
}
|
||||
|
||||
private void ReturnHttpClient(HttpClient client)
|
||||
{
|
||||
if (!client.Online || this.m_httpClients.Count >= 10)
|
||||
{
|
||||
client.SafeDispose();
|
||||
return;
|
||||
}
|
||||
this.m_httpClients.Push(client);
|
||||
}
|
||||
}
|
||||
}
|
@@ -18,17 +18,15 @@ using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using ThingsGateway.Foundation.Core;
|
||||
using ThingsGateway.Foundation.Sockets;
|
||||
|
||||
using HttpClient = System.Net.Http.HttpClient;
|
||||
using HttpMethod = System.Net.Http.HttpMethod;
|
||||
using ThingsGateway.Foundation.Sockets;
|
||||
|
||||
namespace ThingsGateway.Foundation.Http
|
||||
{
|
||||
/// <summary>
|
||||
/// 这是基于<see cref="System.Net.Http.HttpClient"/>的通讯模型。
|
||||
/// </summary>
|
||||
public class HttpClientSlim : DisposableObject
|
||||
public class HttpClientSlim : SetupConfigObject
|
||||
{
|
||||
private readonly System.Net.Http.HttpClient m_httpClient;
|
||||
|
||||
@@ -42,106 +40,16 @@ namespace ThingsGateway.Foundation.Http
|
||||
this.m_httpClient = httpClient;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 配置
|
||||
/// </summary>
|
||||
public TouchSocketConfig Config { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Ioc容器
|
||||
/// </summary>
|
||||
public IContainer Container { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 插件管理器
|
||||
/// </summary>
|
||||
public IPluginsManager PluginsManager { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 日志记录器
|
||||
/// </summary>
|
||||
public ILog Logger { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 通讯客户端
|
||||
/// </summary>
|
||||
public System.Net.Http.HttpClient HttpClient => this.m_httpClient;
|
||||
|
||||
/// <summary>
|
||||
/// 加载配置
|
||||
/// </summary>
|
||||
/// <param name="config"></param>
|
||||
protected virtual void LoadConfig(TouchSocketConfig config)
|
||||
/// <inheritdoc/>
|
||||
protected override void LoadConfig(TouchSocketConfig config)
|
||||
{
|
||||
this.m_httpClient.BaseAddress ??= config.GetValue(TouchSocketConfigExtension.RemoteIPHostProperty);
|
||||
this.Logger ??= this.Container.Resolve<ILog>();
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 配置
|
||||
/// </summary>
|
||||
/// <param name="config"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="ArgumentNullException"></exception>
|
||||
public HttpClientSlim Setup(TouchSocketConfig config)
|
||||
{
|
||||
if (config == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(config));
|
||||
}
|
||||
|
||||
this.ThrowIfDisposed();
|
||||
|
||||
this.BuildConfig(config);
|
||||
|
||||
this.PluginsManager.Raise(nameof(ILoadingConfigPlugin.OnLoadingConfig), this, new ConfigEventArgs(config));
|
||||
this.LoadConfig(this.Config);
|
||||
this.PluginsManager.Raise(nameof(ILoadedConfigPlugin.OnLoadedConfig), this, new ConfigEventArgs(config));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
private void BuildConfig(TouchSocketConfig config)
|
||||
{
|
||||
this.Config = config;
|
||||
|
||||
if (!(config.GetValue(TouchSocketCoreConfigExtension.ContainerProperty) is IContainer container))
|
||||
{
|
||||
container = new Container();
|
||||
}
|
||||
|
||||
if (!container.IsRegistered(typeof(ILog)))
|
||||
{
|
||||
container.RegisterSingleton<ILog, LoggerGroup>();
|
||||
}
|
||||
|
||||
if (!(config.GetValue(TouchSocketCoreConfigExtension.PluginsManagerProperty) is IPluginsManager pluginsManager))
|
||||
{
|
||||
pluginsManager = new PluginsManager(container);
|
||||
}
|
||||
|
||||
if (container.IsRegistered(typeof(IPluginsManager)))
|
||||
{
|
||||
pluginsManager = container.Resolve<IPluginsManager>();
|
||||
}
|
||||
else
|
||||
{
|
||||
container.RegisterSingleton<IPluginsManager>(pluginsManager);
|
||||
}
|
||||
|
||||
if (config.GetValue(TouchSocketCoreConfigExtension.ConfigureContainerProperty) is Action<IContainer> actionContainer)
|
||||
{
|
||||
actionContainer.Invoke(container);
|
||||
}
|
||||
|
||||
if (config.GetValue(TouchSocketCoreConfigExtension.ConfigurePluginsProperty) is Action<IPluginsManager> actionPluginsManager)
|
||||
{
|
||||
pluginsManager.Enable = true;
|
||||
actionPluginsManager.Invoke(pluginsManager);
|
||||
}
|
||||
this.Container = container;
|
||||
this.PluginsManager = pluginsManager;
|
||||
base.LoadConfig(config);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -40,6 +40,16 @@ namespace ThingsGateway.Foundation.Http
|
||||
/// <returns></returns>
|
||||
HttpResponse Request(HttpRequest request, bool onlyRequest = false, int timeout = 10 * 1000, CancellationToken token = default);
|
||||
|
||||
/// <summary>
|
||||
/// 发起请求
|
||||
/// </summary>
|
||||
/// <param name="request">请求体</param>
|
||||
/// <param name="onlyRequest">仅仅请求,而不等待结果</param>
|
||||
/// <param name="timeout">等待超时时间</param>
|
||||
/// <param name="token">结束等待令箭</param>
|
||||
/// <returns></returns>
|
||||
Task<HttpResponse> RequestAsync(HttpRequest request, bool onlyRequest = false, int timeout = 10000, CancellationToken token = default);
|
||||
|
||||
/// <summary>
|
||||
/// 发起请求,并获取数据体
|
||||
/// </summary>
|
||||
@@ -49,5 +59,15 @@ namespace ThingsGateway.Foundation.Http
|
||||
/// <param name="token">结束等待令箭</param>
|
||||
/// <returns></returns>
|
||||
public HttpResponse RequestContent(HttpRequest request, bool onlyRequest = false, int timeout = 10 * 1000, CancellationToken token = default);
|
||||
|
||||
/// <summary>
|
||||
/// 发起请求,并获取数据体
|
||||
/// </summary>
|
||||
/// <param name="request">请求体</param>
|
||||
/// <param name="onlyRequest">仅仅请求,而不等待结果</param>
|
||||
/// <param name="timeout">等待超时时间</param>
|
||||
/// <param name="token">结束等待令箭</param>
|
||||
/// <returns></returns>
|
||||
Task<HttpResponse> RequestContentAsync(HttpRequest request, bool onlyRequest = false, int timeout = 10000, CancellationToken token = default);
|
||||
}
|
||||
}
|
@@ -23,10 +23,13 @@
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// HTTP上下文事件委托
|
||||
/// </summary>
|
||||
/// <typeparam name="TClient"></typeparam>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="e"></param>
|
||||
public delegate void HttpContextEventHandler<TClient>(TClient client, HttpContextEventArgs e);
|
||||
namespace ThingsGateway.Foundation.Http
|
||||
{
|
||||
/// <summary>
|
||||
/// HTTP上下文事件委托
|
||||
/// </summary>
|
||||
/// <typeparam name="TClient"></typeparam>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="e"></param>
|
||||
public delegate Task HttpContextEventHandler<TClient>(TClient client, HttpContextEventArgs e);
|
||||
}
|
||||
|
@@ -45,6 +45,33 @@ namespace ThingsGateway.Foundation.Http
|
||||
|
||||
#region HttpBase
|
||||
|
||||
/// <summary>
|
||||
/// 添加Header参数
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static TRequest AddHeader<TRequest>(this TRequest request, string key, string value) where TRequest : HttpBase
|
||||
{
|
||||
request.Headers.Add(key, value);
|
||||
return request;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加Header参数
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static TRequest AddHeader<TRequest>(this TRequest request, HttpHeaders key, string value) where TRequest : HttpBase
|
||||
{
|
||||
request.Headers.Add(key, value);
|
||||
return request;
|
||||
}
|
||||
|
||||
|
||||
#region 设置内容
|
||||
|
||||
/// <summary>
|
||||
@@ -220,6 +247,19 @@ namespace ThingsGateway.Foundation.Http
|
||||
return request;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加Query参数
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static TRequest AddQuery<TRequest>(this TRequest request, string key, string value) where TRequest : HttpRequest
|
||||
{
|
||||
request.Query.Add(key, value);
|
||||
return request;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 对比不包含参数的Url。其中有任意一方为null,则均返回False。
|
||||
/// </summary>
|
||||
@@ -228,9 +268,14 @@ namespace ThingsGateway.Foundation.Http
|
||||
/// <returns></returns>
|
||||
public static bool UrlEquals<TRequest>(this TRequest request, string url) where TRequest : HttpRequest
|
||||
{
|
||||
return string.IsNullOrEmpty(request.RelativeURL) || string.IsNullOrEmpty(url)
|
||||
? false
|
||||
: request.RelativeURL.Equals(url, StringComparison.CurrentCultureIgnoreCase);
|
||||
if (string.IsNullOrEmpty(request.RelativeURL) || string.IsNullOrEmpty(url))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return request.RelativeURL.Equals(url, StringComparison.CurrentCultureIgnoreCase);
|
||||
}
|
||||
}
|
||||
|
||||
#region 设置函数
|
||||
@@ -374,11 +419,32 @@ namespace ThingsGateway.Foundation.Http
|
||||
/// <returns></returns>
|
||||
public static TResponse SetContentTypeFromFileName<TResponse>(this TResponse response, string fileName) where TResponse : HttpResponse
|
||||
{
|
||||
var contentDisposition = $"attachment;filename={System.Web.HttpUtility.UrlEncode(fileName)}";
|
||||
var contentDisposition = "attachment;" + "filename=" + System.Web.HttpUtility.UrlEncode(fileName);
|
||||
response.Headers.Add(HttpHeaders.ContentDisposition, contentDisposition);
|
||||
return response;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 判断返回的状态码是否为成功。
|
||||
/// </summary>
|
||||
/// <param name="response"></param>
|
||||
/// <param name="status">
|
||||
/// 当不指定具体的状态码时,只要状态码在200-299之间则为<see langword="true"/>。
|
||||
/// 当指定时,状态码不仅必须要在200-299之间,还必须是指定的状态码才会返回<see langword="true"/>。
|
||||
/// </param>
|
||||
/// <returns></returns>
|
||||
public static bool IsSuccess<TResponse>(this TResponse response, int? status = default) where TResponse : HttpResponse
|
||||
{
|
||||
if (status.HasValue)
|
||||
{
|
||||
return response.StatusCode == status && response.StatusCode >= 200 && response.StatusCode < 300;
|
||||
}
|
||||
else
|
||||
{
|
||||
return response.StatusCode >= 200 && response.StatusCode < 300;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置状态,并且附带时间戳。
|
||||
/// </summary>
|
||||
@@ -402,8 +468,8 @@ namespace ThingsGateway.Foundation.Http
|
||||
/// <returns></returns>
|
||||
public static TResponse UrlNotFind<TResponse>(this TResponse response) where TResponse : HttpResponse
|
||||
{
|
||||
response.SetContent("<html><body><h1>404 -RRQM Not Found</h1></body></html>");
|
||||
response.StatusCode = 404;
|
||||
response.SetContent("<html><body><h1>404 -Not Found</h1></body></html>");
|
||||
response.SetStatus(404, "Not Found");
|
||||
response.ContentType = "text/html;charset=utf-8";
|
||||
return response;
|
||||
}
|
||||
@@ -429,7 +495,7 @@ namespace ThingsGateway.Foundation.Http
|
||||
using (var reader = FilePool.GetReader(filePath))
|
||||
{
|
||||
response.SetContentTypeByExtension(Path.GetExtension(filePath));
|
||||
var contentDisposition = $"attachment;filename={System.Web.HttpUtility.UrlEncode(fileName ?? Path.GetFileName(filePath))}";
|
||||
var contentDisposition = "attachment;" + "filename=" + System.Web.HttpUtility.UrlEncode(fileName ?? Path.GetFileName(filePath));
|
||||
response.Headers.Add(HttpHeaders.ContentDisposition, contentDisposition);
|
||||
response.Headers.Add(HttpHeaders.AcceptRanges, "bytes");
|
||||
|
||||
@@ -526,7 +592,7 @@ namespace ThingsGateway.Foundation.Http
|
||||
using (var reader = FilePool.GetReader(filePath))
|
||||
{
|
||||
context.Response.SetContentTypeByExtension(Path.GetExtension(filePath));
|
||||
var contentDisposition = $"attachment;filename={System.Web.HttpUtility.UrlEncode(fileName ?? Path.GetFileName(filePath))}";
|
||||
var contentDisposition = "attachment;" + "filename=" + System.Web.HttpUtility.UrlEncode(fileName ?? Path.GetFileName(filePath));
|
||||
context.Response.Headers.Add(HttpHeaders.ContentDisposition, contentDisposition);
|
||||
context.Response.Headers.Add(HttpHeaders.AcceptRanges, "bytes");
|
||||
|
||||
|
@@ -0,0 +1,37 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace ThingsGateway.Foundation.Http
|
||||
{
|
||||
/// <summary>
|
||||
/// IHttpDeletePlugin
|
||||
/// </summary>
|
||||
[Obsolete("该插件已被弃用,请考虑使用“IHttpPlugin”插件代替使用。本插件将在正式版发布时直接移除。", true)]
|
||||
public interface IHttpDeletePlugin<in TClient> : IPlugin where TClient : IHttpSocketClient
|
||||
{
|
||||
/// <summary>
|
||||
/// 在收到Delete时
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="e"></param>
|
||||
/// <returns></returns>
|
||||
Task OnHttpDelete(TClient client, HttpContextEventArgs e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// IHttpDeletePlugin
|
||||
/// </summary>
|
||||
[Obsolete("该插件已被弃用,请考虑使用“IHttpPlugin”插件代替使用。本插件将在正式版发布时直接移除。", true)]
|
||||
public interface IHttpDeletePlugin : IHttpDeletePlugin<IHttpSocketClient>
|
||||
{
|
||||
}
|
||||
}
|
@@ -0,0 +1,37 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace ThingsGateway.Foundation.Http
|
||||
{
|
||||
/// <summary>
|
||||
/// IHttpGetPlugin
|
||||
/// </summary>
|
||||
[Obsolete("该插件已被弃用,请考虑使用“IHttpPlugin”插件代替使用。本插件将在正式版发布时直接移除。", true)]
|
||||
public interface IHttpGetPlugin<in TClient> : IPlugin where TClient : IHttpSocketClient
|
||||
{
|
||||
/// <summary>
|
||||
/// 在收到Get时
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="e"></param>
|
||||
/// <returns></returns>
|
||||
Task OnHttpGet(TClient client, HttpContextEventArgs e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// IHttpGetPlugin
|
||||
/// </summary>
|
||||
[Obsolete("该插件已被弃用,请考虑使用“IHttpPlugin”插件代替使用。本插件将在正式版发布时直接移除。", true)]
|
||||
public interface IHttpGetPlugin : IHttpGetPlugin<IHttpSocketClient>
|
||||
{
|
||||
}
|
||||
}
|
@@ -31,7 +31,8 @@ namespace ThingsGateway.Foundation.Http
|
||||
public interface IHttpPlugin<in TClient> : IPlugin where TClient : IHttpSocketClient
|
||||
{
|
||||
/// <summary>
|
||||
/// 在收到Http请求时
|
||||
/// 在收到Http请求时。注意:此插件的执行在<see cref="IHttpGetPlugin"/>,<see cref="IHttpPostPlugin"/>,
|
||||
/// <see cref="IHttpDeletePlugin"/>,<see cref="IHttpPutPlugin"/>之前。
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="e"></param>
|
||||
|
@@ -0,0 +1,37 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace ThingsGateway.Foundation.Http
|
||||
{
|
||||
/// <summary>
|
||||
/// IHttpPostPlugin
|
||||
/// </summary>
|
||||
[Obsolete("该插件已被弃用,请考虑使用“IHttpPlugin”插件代替使用。本插件将在正式版发布时直接移除。", true)]
|
||||
public interface IHttpPostPlugin<in TClient> : IPlugin where TClient : IHttpSocketClient
|
||||
{
|
||||
/// <summary>
|
||||
/// 在收到Post时
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="e"></param>
|
||||
/// <returns></returns>
|
||||
Task OnHttpPost(TClient client, HttpContextEventArgs e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// IHttpPostPlugin
|
||||
/// </summary>
|
||||
[Obsolete("该插件已被弃用,请考虑使用“IHttpPlugin”插件代替使用。本插件将在正式版发布时直接移除。", true)]
|
||||
public interface IHttpPostPlugin : IHttpPostPlugin<IHttpSocketClient>
|
||||
{
|
||||
}
|
||||
}
|
@@ -0,0 +1,37 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace ThingsGateway.Foundation.Http
|
||||
{
|
||||
/// <summary>
|
||||
/// IHttpPutPlugin
|
||||
/// </summary>
|
||||
[Obsolete("该插件已被弃用,请考虑使用“IHttpPlugin”插件代替使用。本插件将在正式版发布时直接移除。", true)]
|
||||
public interface IHttpPutPlugin<in TClient> : IPlugin where TClient : IHttpSocketClient
|
||||
{
|
||||
/// <summary>
|
||||
/// 在收到Put时
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="e"></param>
|
||||
/// <returns></returns>
|
||||
Task OnHttpPut(TClient client, HttpContextEventArgs e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// IHttpPutPlugin
|
||||
/// </summary>
|
||||
[Obsolete("该插件已被弃用,请考虑使用“IHttpPlugin”插件代替使用。本插件将在正式版发布时直接移除。", true)]
|
||||
public interface IHttpPutPlugin : IHttpPutPlugin<IHttpSocketClient>
|
||||
{
|
||||
}
|
||||
}
|
@@ -114,6 +114,7 @@ namespace ThingsGateway.Foundation.Http
|
||||
};
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task OnHttpRequest(IHttpSocketClient client, HttpContextEventArgs e)
|
||||
{
|
||||
|
@@ -75,6 +75,7 @@ namespace ThingsGateway.Foundation.Http.WebSockets
|
||||
await this.m_resetEventForRead.WaitOneAsync(token).ConfigureFalseAwait();
|
||||
return new WebSocketReceiveResult(this.ComplateRead, this.m_dataFrame);
|
||||
}
|
||||
|
||||
#if NET6_0_OR_GREATER
|
||||
public async ValueTask<WebSocketReceiveResult> ValueReadAsync(CancellationToken token)
|
||||
{
|
||||
@@ -86,7 +87,9 @@ namespace ThingsGateway.Foundation.Http.WebSockets
|
||||
return new WebSocketReceiveResult(this.ComplateRead, this.m_dataFrame);
|
||||
}
|
||||
#endif
|
||||
|
||||
#region 发送
|
||||
|
||||
public void Send(WSDataFrame dataFrame, bool endOfMessage = true)
|
||||
{
|
||||
this.m_client.SendWithWS(dataFrame, endOfMessage);
|
||||
@@ -132,7 +135,7 @@ namespace ThingsGateway.Foundation.Http.WebSockets
|
||||
return this.m_client.SendWithWSAsync(dataFrame, endOfMessage);
|
||||
}
|
||||
|
||||
#endregion
|
||||
#endregion 发送
|
||||
|
||||
public async Task<bool> TryInputReceiveAsync(WSDataFrame dataFrame)
|
||||
{
|
||||
|
@@ -30,11 +30,10 @@ namespace ThingsGateway.Foundation.Http.WebSockets
|
||||
this.DataFrame = dataFrame;
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
{
|
||||
m_disAction?.Invoke();
|
||||
this.m_disAction?.Invoke();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -47,4 +46,4 @@ namespace ThingsGateway.Foundation.Http.WebSockets
|
||||
/// </summary>
|
||||
public bool IsClosed => this.DataFrame == null;
|
||||
}
|
||||
}
|
||||
}
|
@@ -35,18 +35,14 @@ namespace ThingsGateway.Foundation.Http.WebSockets
|
||||
/// </summary>
|
||||
public WSDataFrameEventHandler<WebSocketClient> Received { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
/// <param name="dataFrame"></param>
|
||||
protected override async Task OnReceivedWSDataFrame(WSDataFrame dataFrame)
|
||||
protected override Task OnReceivedWSDataFrame(WSDataFrameEventArgs e)
|
||||
{
|
||||
if (this.Received != null)
|
||||
{
|
||||
await this.Received.Invoke(this, dataFrame);
|
||||
return this.Received.Invoke(this, e);
|
||||
}
|
||||
|
||||
await base.OnReceivedWSDataFrame(dataFrame);
|
||||
return base.OnReceivedWSDataFrame(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,35 +52,27 @@ namespace ThingsGateway.Foundation.Http.WebSockets
|
||||
public class WebSocketClientBase : HttpClientBase, IWebSocketClient
|
||||
{
|
||||
#region Connect
|
||||
|
||||
/// <summary>
|
||||
/// 请求连接到WebSocket。
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override ITcpClient Connect(int timeout = 5000)
|
||||
{
|
||||
return this.Connect(default, timeout);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// 连接到ws服务器
|
||||
/// </summary>
|
||||
/// <param name="timeout"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
public virtual ITcpClient Connect(CancellationToken token, int timeout = 5000)
|
||||
/// <exception cref="WebSocketConnectException"></exception>
|
||||
public override void Connect(int timeout, CancellationToken token)
|
||||
{
|
||||
lock (this.SyncRoot)
|
||||
try
|
||||
{
|
||||
this.m_semaphoreSlim.Wait(token);
|
||||
if (!this.Online)
|
||||
{
|
||||
base.Connect(timeout);
|
||||
base.Connect(timeout, token);
|
||||
}
|
||||
|
||||
var iPHost = this.Config.GetValue(TouchSocketConfigExtension.RemoteIPHostProperty);
|
||||
var url = iPHost.PathAndQuery;
|
||||
var request = WSTools.GetWSRequest(this.RemoteIPHost.Host, url, this.GetWebSocketVersion(), out var base64Key);
|
||||
this.OnHandshaking(new HttpContextEventArgs(new HttpContext(request)));
|
||||
this.OnHandshaking(new HttpContextEventArgs(new HttpContext(request)))
|
||||
.GetFalseAwaitResult();
|
||||
|
||||
var response = this.Request(request, timeout: timeout, token: token);
|
||||
if (response.StatusCode != 101)
|
||||
@@ -101,47 +89,32 @@ namespace ThingsGateway.Foundation.Http.WebSockets
|
||||
this.SetAdapter(new WebSocketDataHandlingAdapter());
|
||||
this.SetValue(WebSocketFeature.HandshakedProperty, true);
|
||||
response.Flag = true;
|
||||
this.OnHandshaked(new HttpContextEventArgs(new HttpContext(request, response)));
|
||||
return this;
|
||||
Task.Factory.StartNew(PrivateOnHandshaked, new HttpContextEventArgs(new HttpContext(request, response)));
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.m_semaphoreSlim.Release();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
/// <param name="token"></param>
|
||||
/// <param name="timeout"></param>
|
||||
/// <returns></returns>
|
||||
public Task<ITcpClient> ConnectAsync(CancellationToken token, int timeout = 5000)
|
||||
{
|
||||
return Task.Run(() =>
|
||||
{
|
||||
return this.Connect(token, timeout);
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 请求连接到WebSocket。
|
||||
/// </summary>
|
||||
/// <param name="timeout"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="WebSocketConnectException"></exception>
|
||||
public override async Task<ITcpClient> ConnectAsync(int timeout = 5000)
|
||||
public override async Task ConnectAsync(int timeout, CancellationToken token)
|
||||
{
|
||||
try
|
||||
{
|
||||
await this.m_semaphoreSlim.WaitAsync();
|
||||
await this.m_semaphoreSlim.WaitAsync(timeout, token);
|
||||
if (!this.Online)
|
||||
{
|
||||
await base.ConnectAsync(timeout);
|
||||
await base.ConnectAsync(timeout, token);
|
||||
}
|
||||
|
||||
var iPHost = this.Config.GetValue(TouchSocketConfigExtension.RemoteIPHostProperty);
|
||||
var url = iPHost.PathAndQuery;
|
||||
var request = WSTools.GetWSRequest(this.RemoteIPHost.Host, url, this.GetWebSocketVersion(), out var base64Key);
|
||||
this.OnHandshaking(new HttpContextEventArgs(new HttpContext(request)));
|
||||
|
||||
var response = this.Request(request, false, timeout, CancellationToken.None);
|
||||
await this.OnHandshaking(new HttpContextEventArgs(new HttpContext(request)));
|
||||
|
||||
var response = await this.RequestAsync(request, timeout: timeout, token: token);
|
||||
if (response.StatusCode != 101)
|
||||
{
|
||||
throw new WebSocketConnectException($"协议升级失败,信息:{response.StatusMessage},更多信息请捕获WebSocketConnectException异常,获得HttpContext得知。", new HttpContext(request, response));
|
||||
@@ -156,15 +129,13 @@ namespace ThingsGateway.Foundation.Http.WebSockets
|
||||
this.SetAdapter(new WebSocketDataHandlingAdapter());
|
||||
this.SetValue(WebSocketFeature.HandshakedProperty, true);
|
||||
response.Flag = true;
|
||||
this.OnHandshaked(new HttpContextEventArgs(new HttpContext(request, response)));
|
||||
return this;
|
||||
_ = Task.Factory.StartNew(PrivateOnHandshaked, new HttpContextEventArgs(new HttpContext(request, response)));
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.m_semaphoreSlim.Release();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Connect
|
||||
|
||||
#region 字段
|
||||
@@ -185,67 +156,70 @@ namespace ThingsGateway.Foundation.Http.WebSockets
|
||||
/// </summary>
|
||||
public HttpContextEventHandler<WebSocketClientBase> Handshaking { get; set; }
|
||||
|
||||
private Task PrivateOnHandshaked(object obj)
|
||||
{
|
||||
return this.OnHandshaked((HttpContextEventArgs)obj);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 表示完成握手后。
|
||||
/// </summary>
|
||||
/// <param name="e"></param>
|
||||
protected virtual void OnHandshaked(HttpContextEventArgs e)
|
||||
protected virtual async Task OnHandshaked(HttpContextEventArgs e)
|
||||
{
|
||||
this.Handshaked?.Invoke(this, e);
|
||||
|
||||
_ = this.PluginsManager.RaiseAsync(nameof(IWebSocketHandshakedPlugin.OnWebSocketHandshaked), this, e);
|
||||
if (e.Handled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (this.Handshaked != null)
|
||||
{
|
||||
await this.Handshaked.Invoke(this, e);
|
||||
if (e.Handled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
await this.PluginsManager.RaiseAsync(nameof(IWebSocketHandshakedPlugin.OnWebSocketHandshaked), this, e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 表示在即将握手连接时。
|
||||
/// </summary>
|
||||
/// <param name="e"></param>
|
||||
protected virtual void OnHandshaking(HttpContextEventArgs e)
|
||||
protected virtual async Task OnHandshaking(HttpContextEventArgs e)
|
||||
{
|
||||
this.Handshaking?.Invoke(this, e);
|
||||
if (e.Handled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (this.PluginsManager.Raise(nameof(IWebSocketHandshakingPlugin.OnWebSocketHandshaking), this, e))
|
||||
if (this.Handshaking != null)
|
||||
{
|
||||
return;
|
||||
await this.Handshaking.Invoke(this, e).ConfigureFalseAwait();
|
||||
if (e.Handled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
await this.PluginsManager.RaiseAsync(nameof(IWebSocketHandshakingPlugin.OnWebSocketHandshaking), this, e).ConfigureFalseAwait();
|
||||
}
|
||||
|
||||
#endregion 事件
|
||||
|
||||
///// <inheritdoc/>
|
||||
//protected override bool HandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo)
|
||||
//{
|
||||
// if (this.GetHandshaked())
|
||||
// {
|
||||
// var dataFrame = (WSDataFrame)requestInfo;
|
||||
// this.OnReceivedWSDataFrame(dataFrame);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// if (requestInfo is HttpResponse response)
|
||||
// {
|
||||
// response.Flag = false;
|
||||
// base.HandleReceivedData(byteBlock, requestInfo);
|
||||
// SpinWait.SpinUntil(() =>
|
||||
// {
|
||||
// return (bool)response.Flag;
|
||||
// }, 3000);
|
||||
// }
|
||||
// }
|
||||
|
||||
// return false;
|
||||
//}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override async Task ReceivedData(ReceivedDataEventArgs e)
|
||||
{
|
||||
if (this.GetHandshaked())
|
||||
{
|
||||
var dataFrame = (WSDataFrame)e.RequestInfo;
|
||||
await this.OnReceivedWSDataFrame(dataFrame);
|
||||
|
||||
if (this.TryGetValue(WebSocketClientExtension.WebSocketProperty, out var internalWebSocket))
|
||||
{
|
||||
if (await internalWebSocket.TryInputReceiveAsync(dataFrame).ConfigureFalseAwait())
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
await this.OnReceivedWSDataFrame(new WSDataFrameEventArgs(dataFrame));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -280,21 +254,11 @@ namespace ThingsGateway.Foundation.Http.WebSockets
|
||||
/// <summary>
|
||||
/// 当收到WS数据时。
|
||||
/// </summary>
|
||||
/// <param name="dataFrame"></param>
|
||||
protected virtual async Task OnReceivedWSDataFrame(WSDataFrame dataFrame)
|
||||
/// <param name="e"></param>
|
||||
/// <returns></returns>
|
||||
protected virtual async Task OnReceivedWSDataFrame(WSDataFrameEventArgs e)
|
||||
{
|
||||
if (this.TryGetValue(WebSocketClientExtension.WebSocketProperty, out var internalWebSocket))
|
||||
{
|
||||
if (await internalWebSocket.TryInputReceiveAsync(dataFrame))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.PluginsManager.Enable)
|
||||
{
|
||||
await this.PluginsManager.RaiseAsync(nameof(IWebSocketReceivedPlugin.OnWebSocketReceived), this, new WSDataFrameEventArgs(dataFrame));
|
||||
}
|
||||
await this.PluginsManager.RaiseAsync(nameof(IWebSocketReceivedPlugin.OnWebSocketReceived), this, e).ConfigureFalseAwait();
|
||||
}
|
||||
}
|
||||
}
|
@@ -222,10 +222,7 @@ namespace ThingsGateway.Foundation.Http.WebSockets
|
||||
{
|
||||
case FilterResult.Cache:
|
||||
{
|
||||
if (this.m_tempByteBlock == null)
|
||||
{
|
||||
this.m_tempByteBlock = new ByteBlock();
|
||||
}
|
||||
this.m_tempByteBlock ??= new ByteBlock();
|
||||
this.m_tempByteBlock.Write(dataBuffer, offset, length - offset);
|
||||
return;
|
||||
}
|
||||
|
@@ -29,6 +29,6 @@ namespace ThingsGateway.Foundation.Http.WebSockets
|
||||
/// 收到WebSocket数据
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="dataFrame"></param>
|
||||
public delegate Task WSDataFrameEventHandler<TClient>(TClient client, WSDataFrame dataFrame);
|
||||
/// <param name="e"></param>
|
||||
public delegate Task WSDataFrameEventHandler<TClient>(TClient client, WSDataFrameEventArgs e);
|
||||
}
|
@@ -32,7 +32,7 @@ namespace ThingsGateway.Foundation.Http.WebSockets
|
||||
public class WebSocketConnectException : Exception
|
||||
{
|
||||
/// <summary>
|
||||
///构造函数
|
||||
/// WebSocket连接异常
|
||||
/// </summary>
|
||||
/// <param name="mes"></param>
|
||||
/// <param name="context"></param>
|
||||
|
@@ -51,7 +51,7 @@ namespace ThingsGateway.Foundation.Http.WebSockets
|
||||
/// <summary>
|
||||
/// 获取显式WebSocket终端。
|
||||
/// <para>
|
||||
///
|
||||
///
|
||||
/// </para>
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
@@ -76,7 +76,9 @@ namespace ThingsGateway.Foundation.Http.WebSockets
|
||||
{
|
||||
client.RemoveValue(WebSocketProperty);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#endregion DependencyProperty
|
||||
|
||||
/// <summary>
|
||||
/// 发送Close报文。
|
||||
/// </summary>
|
||||
@@ -175,7 +177,6 @@ namespace ThingsGateway.Foundation.Http.WebSockets
|
||||
|
||||
#region 同步发送
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 采用WebSocket协议,发送二进制流数据。
|
||||
/// </summary>
|
||||
|
@@ -22,6 +22,7 @@
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using ThingsGateway.Foundation.Http.WebSockets;
|
||||
|
||||
namespace ThingsGateway.Foundation.Sockets
|
||||
|
@@ -22,6 +22,7 @@
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using ThingsGateway.Foundation.Http.WebSockets;
|
||||
|
||||
namespace ThingsGateway.Foundation.Core
|
||||
|
@@ -15,13 +15,8 @@ namespace ThingsGateway.Foundation.Http.WebSockets
|
||||
/// <summary>
|
||||
/// IWebSocket
|
||||
/// </summary>
|
||||
public interface IWebSocket : IDisposable
|
||||
public interface IWebSocket : IDisposable, IHandshakeObject
|
||||
{
|
||||
/// <summary>
|
||||
/// 表示当前WebSocket是否已经完成连接。
|
||||
/// </summary>
|
||||
bool IsHandshaked { get; }
|
||||
|
||||
/// <summary>
|
||||
/// WebSocket版本
|
||||
/// </summary>
|
||||
@@ -68,6 +63,7 @@ namespace ThingsGateway.Foundation.Http.WebSockets
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
Task<WebSocketReceiveResult> ReadAsync(CancellationToken token);
|
||||
|
||||
#if NET6_0_OR_GREATER
|
||||
/// <summary>
|
||||
/// 值异步等待读取数据
|
||||
@@ -76,6 +72,7 @@ namespace ThingsGateway.Foundation.Http.WebSockets
|
||||
/// <returns></returns>
|
||||
public ValueTask<WebSocketReceiveResult> ValueReadAsync(CancellationToken token);
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// 采用WebSocket协议,发送WS数据。发送结束后,请及时释放<see cref="WSDataFrame"/>
|
||||
/// </summary>
|
||||
|
@@ -30,20 +30,5 @@ namespace ThingsGateway.Foundation.Http.WebSockets
|
||||
/// </summary>
|
||||
public interface IWebSocketClient : IHttpClient
|
||||
{
|
||||
/// <summary>
|
||||
/// 连接到ws服务器
|
||||
/// </summary>
|
||||
/// <param name="token"></param>
|
||||
/// <param name="timeout"></param>
|
||||
/// <returns></returns>
|
||||
ITcpClient Connect(CancellationToken token, int timeout = 5000);
|
||||
|
||||
/// <summary>
|
||||
/// 异步连接到ws服务器
|
||||
/// </summary>
|
||||
/// <param name="token"></param>
|
||||
/// <param name="timeout"></param>
|
||||
/// <returns></returns>
|
||||
Task<ITcpClient> ConnectAsync(CancellationToken token, int timeout = 5000);
|
||||
}
|
||||
}
|
@@ -107,9 +107,11 @@ namespace ThingsGateway.Foundation.Http.WebSockets
|
||||
await method.InvokeAsync(this, os);
|
||||
result = default;
|
||||
break;
|
||||
|
||||
case TaskReturnType.TaskObject:
|
||||
result = await method.InvokeObjectAsync(this, os);
|
||||
break;
|
||||
|
||||
case TaskReturnType.None:
|
||||
default:
|
||||
result = method.Invoke(this, os);
|
||||
|
@@ -76,7 +76,7 @@ namespace ThingsGateway.Foundation.Rpc
|
||||
for (var i = 0; i < callContext.MethodInstance.Filters.Length; i++)
|
||||
{
|
||||
invokeResult = callContext.MethodInstance.Filters[i].ExecutingAsync(callContext, ps, invokeResult)
|
||||
.ConfigureAwait(false).GetAwaiter().GetResult();
|
||||
.GetFalseAwaitResult();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,14 +91,14 @@ namespace ThingsGateway.Foundation.Rpc
|
||||
case TaskReturnType.Task:
|
||||
{
|
||||
callContext.MethodInstance.InvokeAsync(rpcServer, ps)
|
||||
.ConfigureAwait(false).GetAwaiter().GetResult();
|
||||
.GetFalseAwaitResult();
|
||||
}
|
||||
break;
|
||||
|
||||
case TaskReturnType.TaskObject:
|
||||
{
|
||||
invokeResult.Result = callContext.MethodInstance.InvokeObjectAsync(rpcServer, ps)
|
||||
.ConfigureAwait(false).GetAwaiter().GetResult();
|
||||
.GetFalseAwaitResult();
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -123,7 +123,7 @@ namespace ThingsGateway.Foundation.Rpc
|
||||
for (var i = 0; i < callContext.MethodInstance.Filters.Length; i++)
|
||||
{
|
||||
invokeResult = callContext.MethodInstance.Filters[i].ExecutedAsync(callContext, ps, invokeResult)
|
||||
.ConfigureAwait(false).GetAwaiter().GetResult();
|
||||
.GetFalseAwaitResult();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -136,7 +136,7 @@ namespace ThingsGateway.Foundation.Rpc
|
||||
for (var i = 0; i < callContext.MethodInstance.Filters.Length; i++)
|
||||
{
|
||||
invokeResult = callContext.MethodInstance.Filters[i].ExecutExceptionAsync(callContext, ps, invokeResult, ex)
|
||||
.ConfigureAwait(false).GetAwaiter().GetResult();
|
||||
.GetFalseAwaitResult();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -15,7 +15,7 @@ namespace ThingsGateway.Foundation.Serial;
|
||||
/// <summary>
|
||||
/// <inheritdoc cref="ISerialSessionBase"/>
|
||||
/// </summary>
|
||||
public interface ISerialSession : ISerialSessionBase, IClientSender, IPluginObject
|
||||
public interface ISerialSession : ISerialSessionBase, IClientSender, IPluginObject, ISetupConfigObject
|
||||
{
|
||||
/// <summary>
|
||||
/// 成功打开串口
|
||||
@@ -33,11 +33,4 @@ public interface ISerialSession : ISerialSessionBase, IClientSender, IPluginObje
|
||||
/// <exception cref="Exception"></exception>
|
||||
ISerialSession Connect();
|
||||
|
||||
/// <summary>
|
||||
/// 配置服务器
|
||||
/// </summary>
|
||||
/// <param name="config"></param>
|
||||
/// <exception cref="Exception"></exception>
|
||||
ISerialSession Setup(TouchSocketConfig config);
|
||||
|
||||
}
|
||||
|
@@ -17,18 +17,13 @@ namespace ThingsGateway.Foundation.Serial;
|
||||
/// <summary>
|
||||
/// 串口连接接口。
|
||||
/// </summary>
|
||||
public interface ISerialSessionBase : IClient, ISender, IDefaultSender, IPluginObject, IRequsetInfoSender
|
||||
public interface ISerialSessionBase : IClient, ISender, IDefaultSender, IPluginObject, IRequsetInfoSender, IConfigObject, IOnlineClient
|
||||
{
|
||||
/// <summary>
|
||||
/// 是否允许自由调用<see cref="SetDataHandlingAdapter"/>进行赋值。
|
||||
/// </summary>
|
||||
bool CanSetDataHandlingAdapter { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 客户端配置
|
||||
/// </summary>
|
||||
TouchSocketConfig Config { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 数据处理适配器
|
||||
/// </summary>
|
||||
@@ -52,11 +47,6 @@ public interface ISerialSessionBase : IClient, ISender, IDefaultSender, IPluginO
|
||||
SerialPort MainSerialPort { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 判断是否在线
|
||||
/// </summary>
|
||||
bool Online { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 串口描述
|
||||
/// </summary>
|
||||
|
@@ -243,12 +243,12 @@ public class SerialCore : IDisposable, ISender
|
||||
{
|
||||
this.m_semaphoreForSend.Wait();
|
||||
this.m_serialPort.Write(buffer, offset, length);
|
||||
this.m_sendCounter.Increment(length);
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.m_semaphoreForSend.Release();
|
||||
}
|
||||
this.m_sendCounter.Increment(length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -267,13 +267,13 @@ public class SerialCore : IDisposable, ISender
|
||||
await this.m_semaphoreForSend.WaitAsync();
|
||||
|
||||
this.m_serialPort.Write(buffer, offset, length);
|
||||
this.m_sendCounter.Increment(length);
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.m_semaphoreForSend.Release();
|
||||
}
|
||||
|
||||
this.m_sendCounter.Increment(length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@@ -24,24 +24,20 @@ public class SerialSession : SerialSessionBase
|
||||
public ReceivedEventHandler<SerialSession> Received { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override async Task ReceivedData(ReceivedDataEventArgs e)
|
||||
protected override Task ReceivedData(ReceivedDataEventArgs e)
|
||||
{
|
||||
if (this.Received != null)
|
||||
{
|
||||
await this.Received.Invoke(this, e);
|
||||
if (e.Handled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
return this.Received.Invoke(this, e);
|
||||
}
|
||||
await base.ReceivedData(e);
|
||||
return base.ReceivedData(e);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 串口管理
|
||||
/// </summary>
|
||||
public class SerialSessionBase : BaseSerial, ISerialSession
|
||||
public class SerialSessionBase : SetupConfigObject, ISerialSession
|
||||
{
|
||||
static readonly Protocol SerialPort = new("SerialSession");
|
||||
/// <summary>
|
||||
@@ -50,7 +46,6 @@ public class SerialSessionBase : BaseSerial, ISerialSession
|
||||
public SerialSessionBase()
|
||||
{
|
||||
this.Protocol = SerialPort;
|
||||
this.m_serialCore = new InternalSerialCore();
|
||||
}
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
@@ -65,7 +60,7 @@ public class SerialSessionBase : BaseSerial, ISerialSession
|
||||
private DelaySender m_delaySender;
|
||||
private bool m_online => MainSerialPort?.IsOpen == true;
|
||||
private readonly EasyLock m_semaphore = new();
|
||||
private readonly InternalSerialCore m_serialCore;
|
||||
private readonly InternalSerialCore m_serialCore = new();
|
||||
#endregion 变量
|
||||
|
||||
#region 事件
|
||||
@@ -82,9 +77,9 @@ public class SerialSessionBase : BaseSerial, ISerialSession
|
||||
/// <inheritdoc/>
|
||||
public DisconnectEventHandler<ISerialSessionBase> Disconnecting { get; set; }
|
||||
|
||||
private Task PrivateOnConnected(object o)
|
||||
private Task PrivateOnConnected(ConnectedEventArgs o)
|
||||
{
|
||||
return this.OnConnected((ConnectedEventArgs)o);
|
||||
return this.OnConnected(o);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -216,15 +211,9 @@ public class SerialSessionBase : BaseSerial, ISerialSession
|
||||
/// <inheritdoc/>
|
||||
public DateTime LastSendTime => this.GetSerialCore().SendCounter.LastIncrement;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IContainer Container { get; private set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual bool CanSetDataHandlingAdapter => true;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public TouchSocketConfig Config { get; private set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public SingleStreamDataHandlingAdapter DataHandlingAdapter { get; private set; }
|
||||
|
||||
@@ -239,11 +228,6 @@ public class SerialSessionBase : BaseSerial, ISerialSession
|
||||
/// <inheritdoc/>
|
||||
public bool CanSend => this.m_online;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IPluginsManager PluginsManager { get; private set; }
|
||||
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Protocol Protocol { get; set; }
|
||||
|
||||
@@ -256,7 +240,7 @@ public class SerialSessionBase : BaseSerial, ISerialSession
|
||||
/// <inheritdoc/>
|
||||
public virtual void Close(string msg = TouchSocketCoreUtility.Empty)
|
||||
{
|
||||
lock (this.SyncRoot)
|
||||
lock (this.GetSerialCore())
|
||||
{
|
||||
if (this.m_online)
|
||||
{
|
||||
@@ -274,7 +258,7 @@ public class SerialSessionBase : BaseSerial, ISerialSession
|
||||
/// <param name="disposing"></param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
lock (this.SyncRoot)
|
||||
lock (this.GetSerialCore())
|
||||
{
|
||||
if (this.m_online)
|
||||
{
|
||||
@@ -294,8 +278,10 @@ public class SerialSessionBase : BaseSerial, ISerialSession
|
||||
/// </summary>
|
||||
protected void Open()
|
||||
{
|
||||
lock (this.SyncRoot)
|
||||
try
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
this.m_semaphore.Wait();
|
||||
if (this.m_online)
|
||||
{
|
||||
return;
|
||||
@@ -311,17 +297,18 @@ public class SerialSessionBase : BaseSerial, ISerialSession
|
||||
var serialProperty = this.Config.GetValue(SerialConfigExtension.SerialProperty) ?? throw new ArgumentNullException("串口配置不能为空。");
|
||||
this.MainSerialPort.SafeDispose();
|
||||
var serialPort = CreateSerial(serialProperty);
|
||||
this.PrivateOnConnecting(new(serialPort))
|
||||
.ConfigureAwait(false)
|
||||
.GetAwaiter()
|
||||
.GetResult();
|
||||
this.PrivateOnConnecting(new(serialPort)).ConfigureAwait(false).GetAwaiter().GetResult();
|
||||
|
||||
serialPort.Open();
|
||||
|
||||
this.SetSerialPort(serialPort);
|
||||
this.BeginReceive();
|
||||
|
||||
Task.Factory.StartNew(this.PrivateOnConnected, new ConnectedEventArgs());
|
||||
this.PrivateOnConnected(new()).ConfigureAwait(false).GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.m_semaphore.Release();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -379,7 +366,7 @@ public class SerialSessionBase : BaseSerial, ISerialSession
|
||||
/// <param name="msg"></param>
|
||||
protected void BreakOut(bool manual, string msg)
|
||||
{
|
||||
lock (this.SyncRoot)
|
||||
lock (this.GetSerialCore())
|
||||
{
|
||||
if (this.m_online)
|
||||
{
|
||||
@@ -397,17 +384,6 @@ public class SerialSessionBase : BaseSerial, ISerialSession
|
||||
return this.m_serialCore ?? throw new ObjectDisposedException(this.GetType().Name);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int ReceiveBufferSize
|
||||
{
|
||||
get => this.GetSerialCore().ReceiveBufferSize;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int SendBufferSize
|
||||
{
|
||||
get => this.GetSerialCore().SendBufferSize;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual void SetDataHandlingAdapter(SingleStreamDataHandlingAdapter adapter)
|
||||
@@ -420,66 +396,6 @@ public class SerialSessionBase : BaseSerial, ISerialSession
|
||||
this.SetAdapter(adapter);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ISerialSession Setup(TouchSocketConfig config)
|
||||
{
|
||||
if (config == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(config));
|
||||
}
|
||||
|
||||
this.ThrowIfDisposed();
|
||||
|
||||
this.BuildConfig(config);
|
||||
|
||||
this.PluginsManager.Raise(nameof(ILoadingConfigPlugin.OnLoadingConfig), this, new ConfigEventArgs(config));
|
||||
this.LoadConfig(this.Config);
|
||||
this.PluginsManager.Raise(nameof(ILoadedConfigPlugin.OnLoadedConfig), this, new ConfigEventArgs(config));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
private void BuildConfig(TouchSocketConfig config)
|
||||
{
|
||||
this.Config = config;
|
||||
|
||||
if (!(config.GetValue(TouchSocketCoreConfigExtension.ContainerProperty) is IContainer container))
|
||||
{
|
||||
container = new Container();
|
||||
}
|
||||
|
||||
if (!container.IsRegistered(typeof(ILog)))
|
||||
{
|
||||
container.RegisterSingleton<ILog, LoggerGroup>();
|
||||
}
|
||||
|
||||
if (!(config.GetValue(TouchSocketCoreConfigExtension.PluginsManagerProperty) is IPluginsManager pluginsManager))
|
||||
{
|
||||
pluginsManager = new PluginsManager(container);
|
||||
}
|
||||
|
||||
if (container.IsRegistered(typeof(IPluginsManager)))
|
||||
{
|
||||
pluginsManager = container.Resolve<IPluginsManager>();
|
||||
}
|
||||
else
|
||||
{
|
||||
container.RegisterSingleton<IPluginsManager>(pluginsManager);
|
||||
}
|
||||
|
||||
if (config.GetValue(TouchSocketCoreConfigExtension.ConfigureContainerProperty) is Action<IContainer> actionContainer)
|
||||
{
|
||||
actionContainer.Invoke(container);
|
||||
}
|
||||
|
||||
if (config.GetValue(TouchSocketCoreConfigExtension.ConfigurePluginsProperty) is Action<IPluginsManager> actionPluginsManager)
|
||||
{
|
||||
pluginsManager.Enable = true;
|
||||
actionPluginsManager.Invoke(pluginsManager);
|
||||
}
|
||||
this.Container = container;
|
||||
this.PluginsManager = pluginsManager;
|
||||
}
|
||||
|
||||
private void PrivateHandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo)
|
||||
{
|
||||
@@ -521,11 +437,8 @@ public class SerialSessionBase : BaseSerial, ISerialSession
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 加载配置
|
||||
/// </summary>
|
||||
/// <param name="config"></param>
|
||||
protected virtual void LoadConfig(TouchSocketConfig config)
|
||||
/// <inheritdoc/>
|
||||
protected override void LoadConfig(TouchSocketConfig config)
|
||||
{
|
||||
this.SerialProperty = config.GetValue(SerialConfigExtension.SerialProperty);
|
||||
this.Logger ??= this.Container.Resolve<ILog>();
|
||||
|
@@ -225,7 +225,7 @@ public class TcpCore : SocketAsyncEventArgs, IDisposable, ISender
|
||||
{
|
||||
throw new Exception("请先完成Ssl验证授权");
|
||||
}
|
||||
while (true)
|
||||
while (this.m_online)
|
||||
{
|
||||
var byteBlock = new ByteBlock(this.ReceiveBufferSize);
|
||||
try
|
||||
@@ -319,15 +319,16 @@ public class TcpCore : SocketAsyncEventArgs, IDisposable, ISender
|
||||
public virtual void Send(byte[] buffer, int offset, int length)
|
||||
{
|
||||
this.ThrowIfNotConnected();
|
||||
if (this.UseSsl)
|
||||
try
|
||||
{
|
||||
this.SslStream.Write(buffer, offset, length);
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
this.m_semaphoreForSend.Wait();
|
||||
if (this.UseSsl)
|
||||
{
|
||||
this.m_semaphoreForSend.Wait();
|
||||
this.SslStream.Write(buffer, offset, length);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
while (length > 0)
|
||||
{
|
||||
var r = this.m_socket.Send(buffer, offset, length, SocketFlags.None);
|
||||
@@ -339,12 +340,12 @@ public class TcpCore : SocketAsyncEventArgs, IDisposable, ISender
|
||||
length -= r;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.m_semaphoreForSend.Release();
|
||||
}
|
||||
this.m_sendCounter.Increment(length);
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.m_semaphoreForSend.Release();
|
||||
}
|
||||
this.m_sendCounter.Increment(length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -361,16 +362,16 @@ public class TcpCore : SocketAsyncEventArgs, IDisposable, ISender
|
||||
public virtual async Task SendAsync(byte[] buffer, int offset, int length)
|
||||
{
|
||||
this.ThrowIfNotConnected();
|
||||
try
|
||||
{
|
||||
await this.m_semaphoreForSend.WaitAsync();
|
||||
#if NET6_0_OR_GREATER
|
||||
if (this.UseSsl)
|
||||
{
|
||||
await this.SslStream.WriteAsync(new ReadOnlyMemory<byte>(buffer, offset, length), CancellationToken.None);
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
if (this.UseSsl)
|
||||
{
|
||||
await this.SslStream.WriteAsync(new ReadOnlyMemory<byte>(buffer, offset, length), CancellationToken.None);
|
||||
}
|
||||
else
|
||||
{
|
||||
await this.m_semaphoreForSend.WaitAsync();
|
||||
|
||||
while (length > 0)
|
||||
{
|
||||
@@ -383,21 +384,14 @@ public class TcpCore : SocketAsyncEventArgs, IDisposable, ISender
|
||||
length -= r;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.m_semaphoreForSend.Release();
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
if (this.UseSsl)
|
||||
{
|
||||
await this.SslStream.WriteAsync(buffer, offset, length, CancellationToken.None);
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
if (this.UseSsl)
|
||||
{
|
||||
await this.SslStream.WriteAsync(buffer, offset, length, CancellationToken.None);
|
||||
}
|
||||
else
|
||||
{
|
||||
await this.m_semaphoreForSend.WaitAsync();
|
||||
|
||||
while (length > 0)
|
||||
{
|
||||
@@ -410,14 +404,14 @@ public class TcpCore : SocketAsyncEventArgs, IDisposable, ISender
|
||||
length -= r;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.m_semaphoreForSend.Release();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
this.m_sendCounter.Increment(length);
|
||||
this.m_sendCounter.Increment(length);
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.m_semaphoreForSend.Release();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@@ -107,7 +107,7 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
this.m_first = false;
|
||||
}
|
||||
this.MainClient.Close();
|
||||
this.MainClient.Connect((int)this.ConnectTimeout.TotalMilliseconds);
|
||||
this.MainClient.Connect((int)this.ConnectTimeout.TotalMilliseconds, CancellationToken.None);
|
||||
}
|
||||
return Result.Success;
|
||||
}
|
||||
|
@@ -31,7 +31,7 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
/// SocketClient
|
||||
/// </summary>
|
||||
[DebuggerDisplay("Id={Id},IPAdress={IP}:{Port}")]
|
||||
public class SocketClient : BaseSocket, ISocketClient
|
||||
public class SocketClient : ConfigObject, ISocketClient
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
@@ -57,8 +57,6 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
/// <inheritdoc/>
|
||||
public virtual bool CanSetDataHandlingAdapter => true;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public TouchSocketConfig Config { get; private set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IContainer Container { get; private set; }
|
||||
@@ -110,7 +108,8 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool UseSsl { get; private set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override TouchSocketConfig Config => this.Service?.Config;
|
||||
#endregion 属性
|
||||
|
||||
#region Internal
|
||||
@@ -152,10 +151,7 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
return this.OnInitialized();
|
||||
}
|
||||
|
||||
internal void InternalSetConfig(TouchSocketConfig config)
|
||||
{
|
||||
this.Config = config;
|
||||
}
|
||||
|
||||
|
||||
internal void InternalSetContainer(IContainer container)
|
||||
{
|
||||
@@ -234,7 +230,6 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
}
|
||||
}
|
||||
|
||||
base.Dispose(true);
|
||||
}
|
||||
|
||||
private void HandleReceived(TcpCore core, ByteBlock byteBlock)
|
||||
@@ -378,6 +373,7 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
var tcp = this.m_tcpCore;
|
||||
this.m_tcpCore = null;
|
||||
this.Service.ReturnTcpCore(tcp);
|
||||
base.Dispose(true);
|
||||
}
|
||||
}
|
||||
private Task PrivateOnDisconnecting(object obj)
|
||||
@@ -386,22 +382,11 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
}
|
||||
#endregion 事件&委托
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int ReceiveBufferSize
|
||||
{
|
||||
get => this.GetTcpCore().ReceiveBufferSize;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int SendBufferSize
|
||||
{
|
||||
get => this.GetTcpCore().SendBufferSize;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual void Close(string msg = TouchSocketCoreUtility.Empty)
|
||||
{
|
||||
lock (this.SyncRoot)
|
||||
lock (this.GetTcpCore())
|
||||
{
|
||||
if (this.Online)
|
||||
{
|
||||
@@ -483,7 +468,7 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
/// <inheritdoc/>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
lock (this.SyncRoot)
|
||||
lock (this.GetTcpCore())
|
||||
{
|
||||
if (this.Online)
|
||||
{
|
||||
@@ -491,7 +476,6 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
this.BreakOut(true, $"{nameof(Dispose)}主动断开");
|
||||
}
|
||||
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -38,17 +38,13 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
public ReceivedEventHandler<TcpClient> Received { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override async Task ReceivedData(ReceivedDataEventArgs e)
|
||||
protected override Task ReceivedData(ReceivedDataEventArgs e)
|
||||
{
|
||||
if (this.Received != null)
|
||||
{
|
||||
await this.Received.Invoke(this, e);
|
||||
if (e.Handled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
return this.Received.Invoke(this, e);
|
||||
}
|
||||
await base.ReceivedData(e);
|
||||
return base.ReceivedData(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,15 +52,14 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
/// Tcp客户端
|
||||
/// </summary>
|
||||
[System.Diagnostics.DebuggerDisplay("{IP}:{Port}")]
|
||||
public class TcpClientBase : BaseSocket, ITcpClient
|
||||
public class TcpClientBase : SetupConfigObject, ITcpClient
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// Tcp客户端
|
||||
/// </summary>
|
||||
public TcpClientBase()
|
||||
{
|
||||
this.Protocol = Protocol.Tcp;
|
||||
this.m_tcpCore = new InternalTcpCore();
|
||||
}
|
||||
|
||||
#region 变量
|
||||
@@ -72,7 +67,7 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
private DelaySender m_delaySender;
|
||||
private volatile bool m_online;
|
||||
private readonly EasyLock m_semaphore = new();
|
||||
private readonly InternalTcpCore m_tcpCore;
|
||||
private readonly InternalTcpCore m_tcpCore = new InternalTcpCore();
|
||||
#endregion 变量
|
||||
|
||||
#region 事件
|
||||
@@ -223,14 +218,10 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
/// <inheritdoc/>
|
||||
public DateTime LastSendTime => this.GetTcpCore().SendCounter.LastIncrement;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IContainer Container { get; private set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual bool CanSetDataHandlingAdapter => true;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public TouchSocketConfig Config { get; private set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public SingleStreamDataHandlingAdapter DataHandlingAdapter { get; private set; }
|
||||
@@ -247,8 +238,6 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
/// <inheritdoc/>
|
||||
public bool CanSend => this.m_online;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IPluginsManager PluginsManager { get; private set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int Port { get; private set; }
|
||||
@@ -274,7 +263,7 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
/// <inheritdoc/>
|
||||
public virtual void Close(string msg = TouchSocketCoreUtility.Empty)
|
||||
{
|
||||
lock (this.SyncRoot)
|
||||
lock (this.GetTcpCore())
|
||||
{
|
||||
if (this.m_online)
|
||||
{
|
||||
@@ -292,7 +281,7 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
/// <param name="disposing"></param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
lock (this.SyncRoot)
|
||||
lock (this.GetTcpCore())
|
||||
{
|
||||
if (this.m_online)
|
||||
{
|
||||
@@ -311,22 +300,22 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
/// 建立Tcp的连接。
|
||||
/// </summary>
|
||||
/// <param name="timeout"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <exception cref="ObjectDisposedException"></exception>
|
||||
/// <exception cref="ArgumentNullException"></exception>
|
||||
/// <exception cref="Exception"></exception>
|
||||
/// <exception cref="TimeoutException"></exception>
|
||||
protected void TcpConnect(int timeout)
|
||||
protected void TcpConnect(int timeout, CancellationToken token = default)
|
||||
{
|
||||
lock (this.SyncRoot)
|
||||
try
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
this.m_semaphore.Wait(token);
|
||||
if (this.m_online)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (this.DisposedValue)
|
||||
{
|
||||
throw new ObjectDisposedException(this.GetType().FullName);
|
||||
}
|
||||
|
||||
if (this.Config == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(this.Config), "配置文件不能为空。");
|
||||
@@ -335,30 +324,25 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
this.MainSocket.SafeDispose();
|
||||
var socket = this.CreateSocket(iPHost);
|
||||
this.PrivateOnConnecting(new ConnectingEventArgs(socket)).GetFalseAwaitResult();
|
||||
if (timeout == 5000)
|
||||
|
||||
var task = Task.Run(() =>
|
||||
{
|
||||
socket.Connect(iPHost.Host, iPHost.Port);
|
||||
}
|
||||
else
|
||||
}, token);
|
||||
task.ConfigureFalseAwait();
|
||||
if (!task.Wait(timeout, token))
|
||||
{
|
||||
var task = Task.Run(() =>
|
||||
{
|
||||
socket.Connect(iPHost.Host, iPHost.Port);
|
||||
});
|
||||
task.ConfigureAwait(false);
|
||||
if (!task.Wait(timeout))
|
||||
{
|
||||
socket.SafeDispose();
|
||||
throw new TimeoutException();
|
||||
}
|
||||
socket.SafeDispose();
|
||||
throw new TimeoutException();
|
||||
}
|
||||
this.m_online = true;
|
||||
this.SetSocket(socket);
|
||||
this.BeginReceive();
|
||||
this.PrivateOnConnected(new ConnectedEventArgs())
|
||||
.ConfigureAwait(false)
|
||||
.GetAwaiter()
|
||||
.GetResult();
|
||||
this.PrivateOnConnected(new ConnectedEventArgs()).ConfigureAwait(false).GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.m_semaphore.Release();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -383,15 +367,13 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
{
|
||||
try
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
await this.m_semaphore.WaitAsync();
|
||||
if (this.m_online)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (this.DisposedValue)
|
||||
{
|
||||
throw new ObjectDisposedException(this.GetType().FullName);
|
||||
}
|
||||
|
||||
if (this.Config == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(this.Config), "配置文件不能为空。");
|
||||
@@ -458,23 +440,15 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual ITcpClient Connect(int timeout = 5000)
|
||||
public virtual void Connect(int timeout, CancellationToken cancellationToken)
|
||||
{
|
||||
this.TcpConnect(timeout);
|
||||
return this;
|
||||
this.TcpConnect(timeout, cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual async Task<ITcpClient> ConnectAsync(int timeout = 5000)
|
||||
public virtual async Task ConnectAsync(int timeout, CancellationToken cancellationToken)
|
||||
{
|
||||
await this.TcpConnectAsync(timeout);
|
||||
return this;
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
public virtual async Task<ITcpClient> ConnectAsync(int timeout, CancellationToken cancellationToken)
|
||||
{
|
||||
await TcpConnectAsync(timeout, cancellationToken);
|
||||
return this;
|
||||
await this.TcpConnectAsync(timeout, cancellationToken);
|
||||
}
|
||||
|
||||
#endregion Connect
|
||||
@@ -514,7 +488,7 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
/// <param name="msg"></param>
|
||||
protected void BreakOut(bool manual, string msg)
|
||||
{
|
||||
lock (this.SyncRoot)
|
||||
lock (this.GetTcpCore())
|
||||
{
|
||||
if (this.m_online)
|
||||
{
|
||||
@@ -534,18 +508,6 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int ReceiveBufferSize
|
||||
{
|
||||
get => this.GetTcpCore().ReceiveBufferSize;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int SendBufferSize
|
||||
{
|
||||
get => this.GetTcpCore().SendBufferSize;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual void SetDataHandlingAdapter(SingleStreamDataHandlingAdapter adapter)
|
||||
{
|
||||
@@ -557,67 +519,6 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
this.SetAdapter(adapter);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ITcpClient Setup(TouchSocketConfig config)
|
||||
{
|
||||
if (config == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(config));
|
||||
}
|
||||
|
||||
this.ThrowIfDisposed();
|
||||
|
||||
this.BuildConfig(config);
|
||||
|
||||
this.PluginsManager.Raise(nameof(ILoadingConfigPlugin.OnLoadingConfig), this, new ConfigEventArgs(config));
|
||||
this.LoadConfig(this.Config);
|
||||
this.PluginsManager.Raise(nameof(ILoadedConfigPlugin.OnLoadedConfig), this, new ConfigEventArgs(config));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
private void BuildConfig(TouchSocketConfig config)
|
||||
{
|
||||
this.Config = config;
|
||||
|
||||
if (!(config.GetValue(TouchSocketCoreConfigExtension.ContainerProperty) is IContainer container))
|
||||
{
|
||||
container = new Container();
|
||||
}
|
||||
|
||||
if (!container.IsRegistered(typeof(ILog)))
|
||||
{
|
||||
container.RegisterSingleton<ILog, LoggerGroup>();
|
||||
}
|
||||
|
||||
if (!(config.GetValue(TouchSocketCoreConfigExtension.PluginsManagerProperty) is IPluginsManager pluginsManager))
|
||||
{
|
||||
pluginsManager = new PluginsManager(container);
|
||||
}
|
||||
|
||||
if (container.IsRegistered(typeof(IPluginsManager)))
|
||||
{
|
||||
pluginsManager = container.Resolve<IPluginsManager>();
|
||||
}
|
||||
else
|
||||
{
|
||||
container.RegisterSingleton<IPluginsManager>(pluginsManager);
|
||||
}
|
||||
|
||||
if (config.GetValue(TouchSocketCoreConfigExtension.ConfigureContainerProperty) is Action<IContainer> actionContainer)
|
||||
{
|
||||
actionContainer.Invoke(container);
|
||||
}
|
||||
|
||||
if (config.GetValue(TouchSocketCoreConfigExtension.ConfigurePluginsProperty) is Action<IPluginsManager> actionPluginsManager)
|
||||
{
|
||||
pluginsManager.Enable = true;
|
||||
actionPluginsManager.Invoke(pluginsManager);
|
||||
}
|
||||
this.Container = container;
|
||||
this.PluginsManager = pluginsManager;
|
||||
}
|
||||
|
||||
private void PrivateHandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo)
|
||||
{
|
||||
if (this.m_receiver != null)
|
||||
@@ -653,17 +554,14 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
if (this.PluginsManager.GetPluginCount(nameof(ITcpSendingPlugin.OnTcpSending)) > 0)
|
||||
{
|
||||
var args = new SendingEventArgs(buffer, offset, length);
|
||||
await this.PluginsManager.RaiseAsync(nameof(ITcpSendingPlugin.OnTcpSending), this, args).ConfigureAwait(false);
|
||||
await this.PluginsManager.RaiseAsync(nameof(ITcpSendingPlugin.OnTcpSending), this, args).ConfigureFalseAwait();
|
||||
return args.IsPermitOperation;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 加载配置
|
||||
/// </summary>
|
||||
/// <param name="config"></param>
|
||||
protected virtual void LoadConfig(TouchSocketConfig config)
|
||||
/// <inheritdoc/>
|
||||
protected override void LoadConfig(TouchSocketConfig config)
|
||||
{
|
||||
this.RemoteIPHost = config.GetValue(TouchSocketConfigExtension.RemoteIPHostProperty);
|
||||
this.Logger ??= this.Container.Resolve<ILog>();
|
||||
|
@@ -31,52 +31,34 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
/// </summary>
|
||||
public class TcpService<TClient> : TcpServiceBase, ITcpService<TClient> where TClient : SocketClient, new()
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override int SendBufferSize => 1024 * 1024 * 10;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int ReceiveBufferSize => 1024 * 1024 * 10;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// Tcp泛型服务器,由使用者自己指定<see cref="SocketClient"/>类型。
|
||||
/// </summary>
|
||||
public TcpService()
|
||||
{
|
||||
this.m_socketClients = new SocketClientCollection();
|
||||
this.m_getDefaultNewId = this.GetDefaultNewId;
|
||||
}
|
||||
|
||||
#region 变量
|
||||
|
||||
private readonly List<TcpNetworkMonitor> m_monitors = new List<TcpNetworkMonitor>();
|
||||
private readonly SocketClientCollection m_socketClients;
|
||||
private TouchSocketConfig m_config;
|
||||
private IContainer m_container;
|
||||
private readonly SocketClientCollection m_socketClients = new SocketClientCollection();
|
||||
private Func<string> m_getDefaultNewId;
|
||||
private int m_maxCount;
|
||||
private long m_nextId;
|
||||
private IPluginsManager m_pluginsManager;
|
||||
private ServerState m_serverState;
|
||||
|
||||
#endregion 变量
|
||||
|
||||
#region 属性
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override TouchSocketConfig Config => this.m_config;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override IContainer Container => this.m_container;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int MaxCount => this.m_maxCount;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override IEnumerable<TcpNetworkMonitor> Monitors => this.m_monitors.ToArray();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override IPluginsManager PluginsManager => this.m_pluginsManager;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ServerName => this.Config?.GetValue(TouchSocketConfigExtension.ServerNameProperty);
|
||||
|
||||
@@ -368,37 +350,6 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override IService Setup(TouchSocketConfig config)
|
||||
{
|
||||
if (config == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(config));
|
||||
}
|
||||
|
||||
this.ThrowIfDisposed();
|
||||
|
||||
this.BuildConfig(config);
|
||||
|
||||
this.m_pluginsManager.Raise(nameof(ILoadingConfigPlugin.OnLoadingConfig), this, new ConfigEventArgs(config));
|
||||
this.LoadConfig(this.m_config);
|
||||
this.m_pluginsManager.Raise(nameof(ILoadedConfigPlugin.OnLoadedConfig), this, new ConfigEventArgs(config));
|
||||
|
||||
this.Logger ??= this.m_container.Resolve<ILog>();
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
/// <param name="port"></param>
|
||||
public override IService Setup(int port)
|
||||
{
|
||||
var serviceConfig = new TouchSocketConfig();
|
||||
serviceConfig.SetListenIPHosts(new IPHost[] { new IPHost(port) });
|
||||
return this.Setup(serviceConfig);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///<inheritdoc/>
|
||||
/// </summary>
|
||||
@@ -417,7 +368,7 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
/// <exception cref="System.Exception"></exception>
|
||||
public override IService Start()
|
||||
{
|
||||
if (this.m_config is null)
|
||||
if (this.Config is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(this.Config), "Config为null,请先执行Setup");
|
||||
}
|
||||
@@ -476,14 +427,14 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
}
|
||||
this.m_serverState = ServerState.Running;
|
||||
|
||||
this.m_pluginsManager.Raise(nameof(IServerStartedPlugin.OnServerStarted), this, new ServiceStateEventArgs(this.m_serverState, default));
|
||||
this.PluginsManager?.Raise(nameof(IServerStartedPlugin.OnServerStarted), this, new ServiceStateEventArgs(this.m_serverState, default));
|
||||
return this;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.m_serverState = ServerState.Exception;
|
||||
|
||||
this.m_pluginsManager.Raise(nameof(IServerStartedPlugin.OnServerStarted), this, new ServiceStateEventArgs(this.m_serverState, ex) { Message = ex.ToString() });
|
||||
this.PluginsManager?.Raise(nameof(IServerStartedPlugin.OnServerStarted), this, new ServiceStateEventArgs(this.m_serverState, ex) { Message = ex.Message });
|
||||
throw;
|
||||
}
|
||||
}
|
||||
@@ -521,10 +472,8 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
this.Clear();
|
||||
|
||||
this.m_serverState = ServerState.Stopped;
|
||||
if (this.PluginsManager?.Enable == true)
|
||||
{
|
||||
this.m_pluginsManager?.Raise(nameof(IServerStopedPlugin.OnServerStoped), this, new ServiceStateEventArgs(this.m_serverState, default));
|
||||
}
|
||||
this.PluginsManager?.Raise(nameof(IServerStopedPlugin.OnServerStoped), this, new ServiceStateEventArgs(this.m_serverState, default));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -575,10 +524,8 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
this.Clear();
|
||||
|
||||
this.m_serverState = ServerState.Disposed;
|
||||
if (this.PluginsManager?.Enable == true)
|
||||
{
|
||||
this.m_pluginsManager?.Raise(nameof(IServerStopedPlugin.OnServerStoped), this, new ServiceStateEventArgs(this.m_serverState, default));
|
||||
}
|
||||
this.PluginsManager?.Raise(nameof(IServerStopedPlugin.OnServerStoped), this, new ServiceStateEventArgs(this.m_serverState, default));
|
||||
|
||||
this.PluginsManager?.SafeDispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
@@ -593,11 +540,8 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
return new TClient();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 加载配置
|
||||
/// </summary>
|
||||
/// <param name="config"></param>
|
||||
protected virtual void LoadConfig(TouchSocketConfig config)
|
||||
/// <inheritdoc/>
|
||||
protected override void LoadConfig(TouchSocketConfig config)
|
||||
{
|
||||
if (config.GetValue(TouchSocketConfigExtension.GetDefaultNewIdProperty) is Func<string> fun)
|
||||
{
|
||||
@@ -636,48 +580,6 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
}
|
||||
}
|
||||
|
||||
private void BuildConfig(TouchSocketConfig config)
|
||||
{
|
||||
this.m_config = config;
|
||||
|
||||
if (!(config.GetValue(TouchSocketCoreConfigExtension.ContainerProperty) is IContainer container))
|
||||
{
|
||||
container = new Container();
|
||||
}
|
||||
|
||||
if (!container.IsRegistered(typeof(ILog)))
|
||||
{
|
||||
container.RegisterSingleton<ILog, LoggerGroup>();
|
||||
}
|
||||
|
||||
if (!(config.GetValue(TouchSocketCoreConfigExtension.PluginsManagerProperty) is IPluginsManager pluginsManager))
|
||||
{
|
||||
pluginsManager = new PluginsManager(container);
|
||||
}
|
||||
|
||||
if (container.IsRegistered(typeof(IPluginsManager)))
|
||||
{
|
||||
pluginsManager = container.Resolve<IPluginsManager>();
|
||||
}
|
||||
else
|
||||
{
|
||||
container.RegisterSingleton<IPluginsManager>(pluginsManager);
|
||||
}
|
||||
|
||||
if (config.GetValue(TouchSocketCoreConfigExtension.ConfigureContainerProperty) is Action<IContainer> actionContainer)
|
||||
{
|
||||
actionContainer.Invoke(container);
|
||||
}
|
||||
|
||||
if (config.GetValue(TouchSocketCoreConfigExtension.ConfigurePluginsProperty) is Action<IPluginsManager> actionPluginsManager)
|
||||
{
|
||||
pluginsManager.Enable = true;
|
||||
actionPluginsManager.Invoke(pluginsManager);
|
||||
}
|
||||
|
||||
this.m_container = container;
|
||||
this.m_pluginsManager = pluginsManager;
|
||||
}
|
||||
|
||||
private void OnAccepted(SocketAsyncEventArgs e)
|
||||
{
|
||||
@@ -706,8 +608,9 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
this.OnAccepted(e);
|
||||
}
|
||||
}
|
||||
catch
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.Logger.Exception(ex);
|
||||
e.SafeDispose();
|
||||
return;
|
||||
}
|
||||
@@ -742,12 +645,11 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
socket.SendTimeout = monitor.Option.SendTimeout;
|
||||
|
||||
var client = this.GetClientInstence(socket, monitor);
|
||||
client.InternalSetConfig(this.m_config);
|
||||
client.InternalSetContainer(this.m_container);
|
||||
client.InternalSetContainer(this.Container);
|
||||
client.InternalSetService(this);
|
||||
client.InternalSetListenOption(monitor.Option);
|
||||
client.InternalSetSocket(socket);
|
||||
client.InternalSetPluginsManager(this.m_pluginsManager);
|
||||
client.InternalSetPluginsManager(this.PluginsManager);
|
||||
|
||||
if (client.CanSetDataHandlingAdapter)
|
||||
{
|
||||
|
@@ -29,17 +29,9 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
/// <summary>
|
||||
/// Tcp服务器基类
|
||||
/// </summary>
|
||||
public abstract class TcpServiceBase : BaseSocket, ITcpService
|
||||
public abstract class TcpServiceBase : SetupConfigObject, ITcpService
|
||||
{
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
public abstract TouchSocketConfig Config { get; }
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
public abstract IContainer Container { get; }
|
||||
private readonly ConcurrentStack<TcpCore> m_tcpCores = new ConcurrentStack<TcpCore>();
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
@@ -49,12 +41,12 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
public abstract IEnumerable<TcpNetworkMonitor> Monitors { get; }
|
||||
public abstract int MaxCount { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 插件管理器
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
public abstract IPluginsManager PluginsManager { get; }
|
||||
public abstract IEnumerable<TcpNetworkMonitor> Monitors { get; }
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
@@ -65,16 +57,16 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
public abstract ServerState ServerState { get; }
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
public abstract ISocketClientCollection SocketClients { get; }
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// 添加一个地址监听。支持在服务器运行过程中动态添加。
|
||||
/// </summary>
|
||||
public abstract int MaxCount { get; }
|
||||
/// <param name="options"></param>
|
||||
public abstract void AddListen(TcpListenOption options);
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
@@ -91,39 +83,11 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// 移除一个地址监听。支持在服务器运行过程中动态移除。
|
||||
/// </summary>
|
||||
/// <param name="oldId"></param>
|
||||
/// <param name="newId"></param>
|
||||
public abstract void ResetId(string oldId, string newId);
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
/// <param name="serverConfig"></param>
|
||||
/// <returns></returns>
|
||||
public abstract IService Setup(TouchSocketConfig serverConfig);
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
/// <param name="port"></param>
|
||||
/// <returns></returns>
|
||||
public abstract IService Setup(int port);
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public abstract IService Start();
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public abstract IService Stop();
|
||||
|
||||
private ConcurrentStack<TcpCore> m_tcpCores = new ConcurrentStack<TcpCore>();
|
||||
/// <param name="monitor">监听器</param>
|
||||
/// <returns>返回是否已成功移除</returns>
|
||||
public abstract bool RemoveListen(TcpNetworkMonitor monitor);
|
||||
|
||||
/// <summary>
|
||||
/// 租用TcpCore
|
||||
@@ -139,15 +103,12 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
return new InternalTcpCore();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
while (this.m_tcpCores.TryPop(out var tcpCore))
|
||||
{
|
||||
tcpCore.SafeDispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
/// </summary>
|
||||
/// <param name="oldId"></param>
|
||||
/// <param name="newId"></param>
|
||||
public abstract void ResetId(string oldId, string newId);
|
||||
|
||||
/// <summary>
|
||||
/// 归还TcpCore
|
||||
@@ -163,6 +124,25 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
this.m_tcpCores.Push(tcpCore);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
public abstract bool SocketClientExist(string id);
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public abstract IService Start();
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public abstract IService Stop();
|
||||
|
||||
internal Task OnInternalConnected(ISocketClient socketClient, ConnectedEventArgs e)
|
||||
{
|
||||
return this.OnClientConnected(socketClient, e);
|
||||
@@ -188,6 +168,16 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
return this.OnClientReceivedData(socketClient, e);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
while (this.m_tcpCores.TryPop(out var tcpCore))
|
||||
{
|
||||
tcpCore.SafeDispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 客户端连接完成
|
||||
/// </summary>
|
||||
@@ -223,6 +213,7 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
/// <param name="e"></param>
|
||||
protected abstract Task OnClientReceivedData(ISocketClient socketClient, ReceivedDataEventArgs e);
|
||||
|
||||
|
||||
#region Id发送
|
||||
|
||||
/// <summary>
|
||||
@@ -297,24 +288,5 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
|
||||
#endregion Id发送
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
public abstract bool SocketClientExist(string id);
|
||||
|
||||
/// <summary>
|
||||
/// 添加一个地址监听。支持在服务器运行过程中动态添加。
|
||||
/// </summary>
|
||||
/// <param name="options"></param>
|
||||
public abstract void AddListen(TcpListenOption options);
|
||||
|
||||
/// <summary>
|
||||
/// 移除一个地址监听。支持在服务器运行过程中动态移除。
|
||||
/// </summary>
|
||||
/// <param name="monitor">监听器</param>
|
||||
/// <returns>返回是否已成功移除</returns>
|
||||
public abstract bool RemoveListen(TcpNetworkMonitor monitor);
|
||||
}
|
||||
}
|
@@ -56,7 +56,7 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
/// <summary>
|
||||
/// UDP基类服务器。
|
||||
/// </summary>
|
||||
public class UdpSessionBase : BaseSocket, IUdpSession, IPluginObject
|
||||
public class UdpSessionBase : SetupConfigObject, IUdpSession, IPluginObject
|
||||
{
|
||||
private readonly ConcurrentList<SocketAsyncEventArgs> m_socketAsyncs;
|
||||
|
||||
@@ -71,11 +71,6 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
this.Monitor = new UdpNetworkMonitor(null, socket);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int ReceiveBufferSize => 64 * 1024;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int SendBufferSize => 64 * 1024;
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
@@ -87,16 +82,6 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
/// </summary>
|
||||
public virtual bool CanSetDataHandlingAdapter => true;
|
||||
|
||||
/// <summary>
|
||||
/// 获取配置
|
||||
/// </summary>
|
||||
public TouchSocketConfig Config { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
public IContainer Container { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
@@ -117,11 +102,6 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
/// </summary>
|
||||
public UdpNetworkMonitor Monitor { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
public IPluginsManager PluginsManager { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
@@ -212,82 +192,6 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
this.SetAdapter(adapter);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
/// <param name="config"></param>
|
||||
/// <returns></returns>
|
||||
public IService Setup(TouchSocketConfig config)
|
||||
{
|
||||
if (config == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(config));
|
||||
}
|
||||
|
||||
this.ThrowIfDisposed();
|
||||
|
||||
this.BuildConfig(config);
|
||||
|
||||
this.PluginsManager.Raise(nameof(ILoadingConfigPlugin.OnLoadingConfig), this, new ConfigEventArgs(config));
|
||||
this.LoadConfig(this.Config);
|
||||
this.PluginsManager.Raise(nameof(ILoadedConfigPlugin.OnLoadedConfig), this, new ConfigEventArgs(config));
|
||||
return this;
|
||||
}
|
||||
|
||||
private void BuildConfig(TouchSocketConfig config)
|
||||
{
|
||||
this.Config = config;
|
||||
|
||||
if (!(config.GetValue(TouchSocketCoreConfigExtension.ContainerProperty) is IContainer container))
|
||||
{
|
||||
container = new Container();
|
||||
}
|
||||
|
||||
if (!container.IsRegistered(typeof(ILog)))
|
||||
{
|
||||
container.RegisterSingleton<ILog, LoggerGroup>();
|
||||
}
|
||||
|
||||
if (!(config.GetValue(TouchSocketCoreConfigExtension.PluginsManagerProperty) is IPluginsManager pluginsManager))
|
||||
{
|
||||
pluginsManager = new PluginsManager(container);
|
||||
}
|
||||
|
||||
if (container.IsRegistered(typeof(IPluginsManager)))
|
||||
{
|
||||
pluginsManager = container.Resolve<IPluginsManager>();
|
||||
}
|
||||
else
|
||||
{
|
||||
container.RegisterSingleton<IPluginsManager>(pluginsManager);
|
||||
}
|
||||
|
||||
if (config.GetValue(TouchSocketCoreConfigExtension.ConfigureContainerProperty) is Action<IContainer> actionContainer)
|
||||
{
|
||||
actionContainer.Invoke(container);
|
||||
}
|
||||
|
||||
if (config.GetValue(TouchSocketCoreConfigExtension.ConfigurePluginsProperty) is Action<IPluginsManager> actionPluginsManager)
|
||||
{
|
||||
pluginsManager.Enable = true;
|
||||
actionPluginsManager.Invoke(pluginsManager);
|
||||
}
|
||||
|
||||
this.Container = container;
|
||||
this.PluginsManager = pluginsManager;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 通过端口配置
|
||||
/// </summary>
|
||||
/// <param name="port"></param>
|
||||
public IService Setup(int port)
|
||||
{
|
||||
var serverConfig = new TouchSocketConfig();
|
||||
serverConfig.SetBindIPHost(new IPHost(port));
|
||||
return this.Setup(serverConfig);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 启动服务
|
||||
/// </summary>
|
||||
@@ -330,13 +234,13 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
|
||||
this.ServerState = ServerState.Running;
|
||||
|
||||
this.PluginsManager.Raise(nameof(IServerStartedPlugin.OnServerStarted), this, new ServiceStateEventArgs(this.ServerState, default));
|
||||
this.PluginsManager?.Raise(nameof(IServerStartedPlugin.OnServerStarted), this, new ServiceStateEventArgs(this.ServerState, default));
|
||||
return this;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.ServerState = ServerState.Exception;
|
||||
this.PluginsManager.Raise(nameof(IServerStartedPlugin.OnServerStarted), this, new ServiceStateEventArgs(this.ServerState, ex) { Message = ex.ToString() });
|
||||
this.PluginsManager?.Raise(nameof(IServerStartedPlugin.OnServerStarted), this, new ServiceStateEventArgs(this.ServerState, ex) { Message = ex.ToString() });
|
||||
throw;
|
||||
}
|
||||
}
|
||||
@@ -355,7 +259,7 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
}
|
||||
this.m_socketAsyncs.Clear();
|
||||
|
||||
this.PluginsManager.Raise(nameof(IServerStartedPlugin.OnServerStarted), this, new ServiceStateEventArgs(this.ServerState, default));
|
||||
this.PluginsManager?.Raise(nameof(IServerStartedPlugin.OnServerStarted), this, new ServiceStateEventArgs(this.ServerState, default));
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -378,7 +282,7 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
}
|
||||
this.m_socketAsyncs.Clear();
|
||||
|
||||
this.PluginsManager.Raise(nameof(IServerStartedPlugin.OnServerStarted), this, new ServiceStateEventArgs(this.ServerState, default));
|
||||
this.PluginsManager?.Raise(nameof(IServerStartedPlugin.OnServerStarted), this, new ServiceStateEventArgs(this.ServerState, default));
|
||||
}
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
@@ -405,11 +309,8 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 加载配置
|
||||
/// </summary>
|
||||
/// <param name="config"></param>
|
||||
protected virtual void LoadConfig(TouchSocketConfig config)
|
||||
/// <inheritdoc/>
|
||||
protected override void LoadConfig(TouchSocketConfig config)
|
||||
{
|
||||
this.Logger = this.Container.Resolve<ILog>();
|
||||
this.RemoteIPHost = config.GetValue(TouchSocketConfigExtension.RemoteIPHostProperty);
|
||||
@@ -448,10 +349,7 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
|
||||
if (this.Config != null)
|
||||
{
|
||||
if (this.Config.GetValue(DataHandlingAdapterExtension.MaxPackageSizeProperty) is int v1)
|
||||
{
|
||||
adapter.MaxPackageSize = v1;
|
||||
}
|
||||
adapter.Config(this.Config);
|
||||
}
|
||||
adapter.Logger = this.Logger;
|
||||
adapter.OnLoaded(this);
|
||||
@@ -501,7 +399,7 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
var eventArg = new SocketAsyncEventArgs();
|
||||
this.m_socketAsyncs.Add(eventArg);
|
||||
eventArg.Completed += this.IO_Completed;
|
||||
var byteBlock = new ByteBlock(this.ReceiveBufferSize);
|
||||
var byteBlock = new ByteBlock(1024 * 64);
|
||||
eventArg.UserToken = byteBlock;
|
||||
eventArg.SetBuffer(byteBlock.Buffer, 0, byteBlock.Capacity);
|
||||
eventArg.RemoteEndPoint = iPHost.EndPoint;
|
||||
@@ -518,7 +416,7 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
var eventArg = new SocketAsyncEventArgs();
|
||||
this.m_socketAsyncs.Add(eventArg);
|
||||
eventArg.Completed += this.IO_Completed;
|
||||
var byteBlock = new ByteBlock(this.ReceiveBufferSize);
|
||||
var byteBlock = new ByteBlock(1024 * 64);
|
||||
eventArg.UserToken = byteBlock;
|
||||
eventArg.SetBuffer(byteBlock.Buffer, 0, byteBlock.Capacity);
|
||||
eventArg.RemoteEndPoint = iPHost.EndPoint;
|
||||
@@ -734,7 +632,7 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
|
||||
this.HandleBuffer(e.RemoteEndPoint, byteBlock);
|
||||
|
||||
var newByteBlock = new ByteBlock(this.ReceiveBufferSize);
|
||||
var newByteBlock = new ByteBlock(1024 * 64);
|
||||
e.UserToken = newByteBlock;
|
||||
e.SetBuffer(newByteBlock.Buffer, 0, newByteBlock.Buffer.Length);
|
||||
|
||||
|
@@ -49,13 +49,6 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
/// <param name="e"></param>
|
||||
public delegate Task DisconnectEventHandler<TClient>(TClient client, DisconnectEventArgs e);
|
||||
|
||||
/// <summary>
|
||||
/// 显示信息
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="e"></param>
|
||||
public delegate void MessageEventHandler<TClient>(TClient client, MsgPermitEventArgs e);
|
||||
|
||||
/// <summary>
|
||||
/// 接收数据
|
||||
/// </summary>
|
||||
@@ -63,14 +56,6 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
/// <param name="e"></param>
|
||||
public delegate Task ReceivedEventHandler<TClient>(TClient client, ReceivedDataEventArgs e);
|
||||
|
||||
/// <summary>
|
||||
/// 普通通知
|
||||
/// </summary>
|
||||
/// <typeparam name="TClient"></typeparam>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="e"></param>
|
||||
public delegate void TouchSocketEventHandler<TClient>(TClient client, PluginEventArgs e);
|
||||
|
||||
/// <summary>
|
||||
/// Udp接收
|
||||
/// </summary>
|
||||
|
@@ -119,8 +119,8 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
|
||||
#region 连接
|
||||
|
||||
/// <inheritdoc cref="ITcpClient.Connect(int)"/>
|
||||
public static TClient Connect<TClient>(this TClient client, string ipHost, int timeout = 5000) where TClient : ITcpClient
|
||||
/// <inheritdoc cref="IConnectObject.Connect(int, System.Threading.CancellationToken)"/>
|
||||
public static TClient Connect<TClient>(this TClient client, IPHost ipHost, int timeout = 5000) where TClient : ITcpClient
|
||||
{
|
||||
TouchSocketConfig config;
|
||||
if (client.Config == null)
|
||||
@@ -138,8 +138,8 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
return client;
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="ITcpClient.ConnectAsync(int)"/>
|
||||
public static async Task<TClient> ConnectAsync<TClient>(this TClient client, string ipHost, int timeout = 5000) where TClient : ITcpClient
|
||||
/// <inheritdoc cref="IConnectObject.ConnectAsync(int, System.Threading.CancellationToken)"/>
|
||||
public static async Task<TClient> ConnectAsync<TClient>(this TClient client, IPHost ipHost, int timeout = 5000) where TClient : ITcpClient
|
||||
{
|
||||
TouchSocketConfig config;
|
||||
if (client.Config == null)
|
||||
|
@@ -0,0 +1,88 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:http://rrqm_home.gitee.io/touchsocket/
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace ThingsGateway.Foundation.Sockets
|
||||
{
|
||||
/// <summary>
|
||||
/// ConnectObjectExtension
|
||||
/// </summary>
|
||||
public static class ConnectObjectExtension
|
||||
{
|
||||
#region 连接
|
||||
|
||||
/// <inheritdoc cref="IConnectObject.Connect(int, CancellationToken)"/>
|
||||
public static void Connect(this IConnectObject client, int timeout = 5000)
|
||||
{
|
||||
client.Connect(timeout, CancellationToken.None);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IConnectObject.ConnectAsync(int, CancellationToken)"/>
|
||||
public static async Task ConnectAsync(this IConnectObject client, int timeout = 5000)
|
||||
{
|
||||
await client.ConnectAsync(timeout, CancellationToken.None);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 尝试连接。不会抛出异常。
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="timeout"></param>
|
||||
/// <returns></returns>
|
||||
public static Result TryConnect(this IConnectObject client, int timeout = 5000)
|
||||
{
|
||||
try
|
||||
{
|
||||
client.Connect(timeout);
|
||||
return new Result(ResultCode.Success);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new Result(ResultCode.Exception, ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 尝试连接。不会抛出异常。
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="timeout"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task<Result> TryConnectAsync(this IConnectObject client, int timeout = 5000)
|
||||
{
|
||||
try
|
||||
{
|
||||
await client.ConnectAsync(timeout);
|
||||
return new Result(ResultCode.Success);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new Result(ResultCode.Exception, ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion 连接
|
||||
}
|
||||
|
||||
}
|
@@ -53,7 +53,19 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
{
|
||||
return pluginsManager.Add<CheckClearPlugin<TClient>>();
|
||||
}
|
||||
|
||||
#region Reconnection
|
||||
/// <summary>
|
||||
/// 使用断线重连。
|
||||
/// </summary>
|
||||
/// <typeparam name="TClient"></typeparam>
|
||||
/// <param name="pluginsManager"></param>
|
||||
/// <returns></returns>
|
||||
public static ReconnectionPlugin<TClient> UseReconnection<TClient>(this IPluginsManager pluginsManager) where TClient : class, ITcpClient
|
||||
{
|
||||
var reconnectionPlugin = new ReconnectionPlugin<TClient>();
|
||||
pluginsManager.Add(reconnectionPlugin);
|
||||
return reconnectionPlugin;
|
||||
}
|
||||
/// <summary>
|
||||
/// 使用断线重连。
|
||||
/// <para>该效果仅客户端在完成首次连接,且为被动断开时有效。</para>
|
||||
@@ -66,7 +78,6 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
/// <returns></returns>
|
||||
public static ReconnectionPlugin<ITcpClient> UseReconnection(this IPluginsManager pluginsManager, int tryCount = 10, bool printLog = false, int sleepTime = 1000, Action<ITcpClient> successCallback = null)
|
||||
{
|
||||
var first = true;
|
||||
var reconnectionPlugin = new ReconnectionPlugin<ITcpClient>();
|
||||
reconnectionPlugin.SetConnectAction(async client =>
|
||||
{
|
||||
@@ -81,13 +92,8 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
}
|
||||
else
|
||||
{
|
||||
if (first)
|
||||
{
|
||||
await Task.Delay(500);
|
||||
first = false;
|
||||
}
|
||||
client.Connect();
|
||||
first = true;
|
||||
await Task.Delay(1000);
|
||||
await client.ConnectAsync();
|
||||
}
|
||||
successCallback?.Invoke(client);
|
||||
return true;
|
||||
@@ -107,18 +113,6 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
return reconnectionPlugin;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 使用指定刻度爱你类型的断线重连
|
||||
/// </summary>
|
||||
/// <param name="pluginsManager"></param>
|
||||
/// <returns></returns>
|
||||
public static ReconnectionPlugin<TClient> UseReconnection<TClient>(this IPluginsManager pluginsManager) where TClient : class, ITcpClient
|
||||
{
|
||||
var reconnectionPlugin = new ReconnectionPlugin<TClient>();
|
||||
pluginsManager.Add(reconnectionPlugin);
|
||||
return reconnectionPlugin;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 使用断线重连。
|
||||
/// <para>该效果仅客户端在完成首次连接,且为被动断开时有效。</para>
|
||||
@@ -132,7 +126,6 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
Func<ITcpClient, int, Exception, bool> failCallback = default,
|
||||
Action<ITcpClient> successCallback = default)
|
||||
{
|
||||
var first = true;
|
||||
var reconnectionPlugin = new ReconnectionPlugin<ITcpClient>();
|
||||
reconnectionPlugin.SetConnectAction(async client =>
|
||||
{
|
||||
@@ -147,13 +140,8 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
}
|
||||
else
|
||||
{
|
||||
if (first)
|
||||
{
|
||||
await Task.Delay(500);
|
||||
first = false;
|
||||
}
|
||||
client.Connect();
|
||||
first = true;
|
||||
await Task.Delay(1000);
|
||||
await client.ConnectAsync();
|
||||
}
|
||||
|
||||
successCallback?.Invoke(client);
|
||||
@@ -172,6 +160,7 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
pluginsManager.Add(reconnectionPlugin);
|
||||
return reconnectionPlugin;
|
||||
}
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,59 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:http://rrqm_home.gitee.io/touchsocket/
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace ThingsGateway.Foundation.Sockets
|
||||
{
|
||||
/// <summary>
|
||||
/// 握手状态。
|
||||
/// </summary>
|
||||
public enum HandshakeStatus : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// 标识没有任何操作
|
||||
/// </summary>
|
||||
None,
|
||||
|
||||
/// <summary>
|
||||
/// 标识正在握手
|
||||
/// </summary>
|
||||
Handshaking,
|
||||
|
||||
/// <summary>
|
||||
/// 标识已经完成握手
|
||||
/// </summary>
|
||||
Handshaked,
|
||||
|
||||
/// <summary>
|
||||
/// 标识正在执行关闭
|
||||
/// </summary>
|
||||
Closing,
|
||||
|
||||
/// <summary>
|
||||
/// 标识已经关闭
|
||||
/// </summary>
|
||||
Closed
|
||||
}
|
||||
|
||||
}
|
@@ -26,22 +26,13 @@
|
||||
namespace ThingsGateway.Foundation.Sockets
|
||||
{
|
||||
/// <summary>
|
||||
/// 通讯基类
|
||||
/// 具有握手连接的对象。
|
||||
/// </summary>
|
||||
public abstract class BaseSocket : DependencyObject, ISocket
|
||||
public interface IHandshakeObject
|
||||
{
|
||||
/// <summary>
|
||||
/// 同步根。
|
||||
/// 只是当前客户端是否已经完成握手连接。
|
||||
/// </summary>
|
||||
protected readonly object SyncRoot = new object();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public abstract int SendBufferSize { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public abstract int ReceiveBufferSize { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ILog Logger { get; set; }
|
||||
bool IsHandshaked { get; }
|
||||
}
|
||||
}
|
@@ -28,7 +28,7 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
/// <summary>
|
||||
/// 终端接口
|
||||
/// </summary>
|
||||
public interface IClient : IDependencyObject, IDisposable, ISocket
|
||||
public interface IClient : IDependencyObject, IDisposable, ILoggerObject
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取一个同步数据接收器
|
||||
|
@@ -0,0 +1,51 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:http://rrqm_home.gitee.io/touchsocket/
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace ThingsGateway.Foundation.Sockets
|
||||
{
|
||||
/// <summary>
|
||||
/// 具有连接动作的对象
|
||||
/// </summary>
|
||||
public interface IConnectObject
|
||||
{
|
||||
/// <summary>
|
||||
/// 连接
|
||||
/// </summary>
|
||||
/// <param name="timeout">最大等待时间</param>
|
||||
/// <param name="token">可取消令箭</param>
|
||||
/// <exception cref="TimeoutException"></exception>
|
||||
/// <exception cref="Exception"></exception>
|
||||
void Connect(int timeout, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// 异步连接
|
||||
/// </summary>
|
||||
/// <param name="timeout">最大等待时间</param>
|
||||
/// <param name="token">可取消令箭</param>
|
||||
/// <exception cref="TimeoutException"></exception>
|
||||
/// <exception cref="Exception"></exception>
|
||||
Task ConnectAsync(int timeout, CancellationToken token);
|
||||
}
|
||||
}
|
@@ -0,0 +1,38 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:http://rrqm_home.gitee.io/touchsocket/
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace ThingsGateway.Foundation.Sockets
|
||||
{
|
||||
/// <summary>
|
||||
/// 标识在线状态的对象
|
||||
/// </summary>
|
||||
public interface IOnlineClient
|
||||
{
|
||||
/// <summary>
|
||||
/// 判断是否在线
|
||||
/// </summary>
|
||||
bool Online { get; }
|
||||
}
|
||||
}
|
@@ -28,31 +28,18 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
/// <summary>
|
||||
/// 服务器接口
|
||||
/// </summary>
|
||||
public interface IService : IDisposable
|
||||
public interface IService : IDisposable, ISetupConfigObject
|
||||
{
|
||||
/// <summary>
|
||||
/// 服务器状态
|
||||
/// </summary>
|
||||
ServerState ServerState { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取服务器配置
|
||||
/// </summary>
|
||||
TouchSocketConfig Config { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 名称
|
||||
/// </summary>
|
||||
string ServerName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 配置服务器
|
||||
/// </summary>
|
||||
/// <param name="serverConfig">配置</param>
|
||||
/// <exception cref="Exception"></exception>
|
||||
/// <returns>设置的服务实例</returns>
|
||||
IService Setup(TouchSocketConfig serverConfig);
|
||||
|
||||
/// <summary>
|
||||
/// 启动
|
||||
/// </summary>
|
||||
|
@@ -28,7 +28,7 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
/// <summary>
|
||||
/// Tcp客户端终端接口
|
||||
/// </summary>
|
||||
public interface ITcpClient : ITcpClientBase, IClientSender, IPluginObject
|
||||
public interface ITcpClient : ITcpClientBase, IClientSender, IPluginObject, ISetupConfigObject, IConnectObject
|
||||
{
|
||||
/// <summary>
|
||||
/// 成功连接到服务器
|
||||
@@ -45,25 +45,5 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
/// </summary>
|
||||
IPHost RemoteIPHost { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 连接服务器
|
||||
/// </summary>
|
||||
/// <exception cref="TimeoutException"></exception>
|
||||
/// <exception cref="Exception"></exception>
|
||||
ITcpClient Connect(int timeout = 5000);
|
||||
|
||||
/// <summary>
|
||||
/// 异步连接服务器
|
||||
/// </summary>
|
||||
/// <exception cref="TimeoutException"></exception>
|
||||
/// <exception cref="Exception"></exception>
|
||||
Task<ITcpClient> ConnectAsync(int timeout = 5000);
|
||||
|
||||
/// <summary>
|
||||
/// 配置服务器
|
||||
/// </summary>
|
||||
/// <param name="config"></param>
|
||||
/// <exception cref="Exception"></exception>
|
||||
ITcpClient Setup(TouchSocketConfig config);
|
||||
}
|
||||
}
|
@@ -33,18 +33,13 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
/// 注意:该接口并不仅表示客户端。<see cref="SocketClient"/>也实现了该接口。
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public interface ITcpClientBase : IClient, ISender, IDefaultSender, IPluginObject, IRequsetInfoSender
|
||||
public interface ITcpClientBase : IClient, ISender, IDefaultSender, IPluginObject, IRequsetInfoSender, IConfigObject, IOnlineClient
|
||||
{
|
||||
/// <summary>
|
||||
/// 是否允许自由调用<see cref="SetDataHandlingAdapter"/>进行赋值。
|
||||
/// </summary>
|
||||
bool CanSetDataHandlingAdapter { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 客户端配置
|
||||
/// </summary>
|
||||
TouchSocketConfig Config { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 数据处理适配器
|
||||
/// </summary>
|
||||
@@ -77,12 +72,6 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
/// </summary>
|
||||
Socket MainSocket { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 判断是否在线
|
||||
/// <para>该属性仅表示Tcp状态是否在线</para>
|
||||
/// </summary>
|
||||
bool Online { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 端口号
|
||||
/// </summary>
|
||||
|
@@ -28,13 +28,8 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
/// <summary>
|
||||
/// UDP会话
|
||||
/// </summary>
|
||||
public interface IUdpSession : IService, IClient, IClientSender, IUdpClientSender, IDefaultSender, IUdpDefaultSender
|
||||
public interface IUdpSession : IService, IClient, IClientSender, IUdpClientSender, IDefaultSender, IUdpDefaultSender, ISetupConfigObject
|
||||
{
|
||||
/// <summary>
|
||||
/// 插件管理器
|
||||
/// </summary>
|
||||
IPluginsManager PluginsManager { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否允许自由调用<see cref="SetDataHandlingAdapter"/>进行赋值。
|
||||
/// </summary>
|
||||
|
@@ -70,13 +70,13 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
public TimeSpan Tick { get; set; } = TimeSpan.FromSeconds(60);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Task OnTcpConnected(TClient client, ConnectedEventArgs e)
|
||||
public async Task OnTcpConnected(TClient client, ConnectedEventArgs e)
|
||||
{
|
||||
Task.Run(async () =>
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
await Task.Delay(this.Tick);
|
||||
await Task.Delay(TimeSpan.FromMilliseconds(this.Tick.TotalMilliseconds / 10.0)).ConfigureFalseAwait();
|
||||
if (!client.Online)
|
||||
{
|
||||
return;
|
||||
@@ -105,7 +105,7 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
}
|
||||
});
|
||||
|
||||
return e.InvokeNext();
|
||||
await e.InvokeNext();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@@ -31,6 +31,8 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
[PluginOption(Singleton = true, NotRegister = true)]
|
||||
public sealed class ReconnectionPlugin<TClient> : PluginBase where TClient : class, ITcpClient
|
||||
{
|
||||
private bool m_polling;
|
||||
|
||||
/// <summary>
|
||||
/// 重连插件
|
||||
/// </summary>
|
||||
@@ -48,15 +50,12 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
this.ActionForCheck = (c, i) =>
|
||||
{
|
||||
return Task.FromResult<bool?>(c.Online);
|
||||
};
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
protected override void Loaded(IPluginsManager pluginsManager)
|
||||
{
|
||||
base.Loaded(pluginsManager);
|
||||
pluginsManager.Add<object, ConfigEventArgs>(nameof(ILoadedConfigPlugin.OnLoadedConfig), this.OnLoadedConfig);
|
||||
pluginsManager.Add<TClient, DisconnectEventArgs>(nameof(ITcpDisconnectedPlugin.OnTcpDisconnected), this.OnTcpDisconnected);
|
||||
}
|
||||
private bool m_polling;
|
||||
|
||||
/// <summary>
|
||||
/// 每个周期可执行的委托。用于检验客户端活性。返回true表示存活,返回
|
||||
@@ -73,6 +72,85 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
/// </summary>
|
||||
public TimeSpan Tick { get; set; } = TimeSpan.FromSeconds(1);
|
||||
|
||||
/// <summary>
|
||||
/// 每个周期可执行的委托。返回值为True标识客户端存活。返回False,表示失活,立即重连。返回null时,表示跳过此次检验。
|
||||
/// </summary>
|
||||
/// <param name="actionForCheck"></param>
|
||||
/// <returns></returns>
|
||||
public ReconnectionPlugin<TClient> SetActionForCheck(Func<TClient, int, Task<bool?>> actionForCheck)
|
||||
{
|
||||
this.ActionForCheck = actionForCheck;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 每个周期可执行的委托。返回值为True标识客户端存活。返回False,表示失活,立即重连。返回null时,表示跳过此次检验。
|
||||
/// </summary>
|
||||
/// <param name="actionForCheck"></param>
|
||||
/// <returns></returns>
|
||||
public ReconnectionPlugin<TClient> SetActionForCheck(Func<TClient, int, bool?> actionForCheck)
|
||||
{
|
||||
this.ActionForCheck = async (c, i) =>
|
||||
{
|
||||
await EasyTask.CompletedTask;
|
||||
return actionForCheck.Invoke(c, i);
|
||||
};
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置连接动作
|
||||
/// </summary>
|
||||
/// <param name="tryConnect"></param>
|
||||
/// <returns>无论如何,只要返回True,则结束本轮尝试</returns>
|
||||
public ReconnectionPlugin<TClient> SetConnectAction(Func<TClient, Task<bool>> tryConnect)
|
||||
{
|
||||
this.ActionForConnect = tryConnect;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置连接动作
|
||||
/// </summary>
|
||||
/// <param name="tryConnect"></param>
|
||||
/// <returns>无论如何,只要返回True,则结束本轮尝试</returns>
|
||||
public ReconnectionPlugin<TClient> SetConnectAction(Func<TClient, bool> tryConnect)
|
||||
{
|
||||
this.ActionForConnect = (c) =>
|
||||
{
|
||||
return Task.FromResult(tryConnect.Invoke(c));
|
||||
};
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检验时间间隔
|
||||
/// </summary>
|
||||
/// <param name="tick"></param>
|
||||
/// <returns></returns>
|
||||
public ReconnectionPlugin<TClient> SetTick(TimeSpan tick)
|
||||
{
|
||||
this.Tick = tick;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 使用轮询保持活性。
|
||||
/// </summary>
|
||||
public ReconnectionPlugin<TClient> UsePolling()
|
||||
{
|
||||
this.m_polling = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Loaded(IPluginsManager pluginsManager)
|
||||
{
|
||||
base.Loaded(pluginsManager);
|
||||
pluginsManager.Add<object, ConfigEventArgs>(nameof(ILoadedConfigPlugin.OnLoadedConfig), this.OnLoadedConfig);
|
||||
pluginsManager.Add<TClient, DisconnectEventArgs>(nameof(ITcpDisconnectedPlugin.OnTcpDisconnected), this.OnTcpDisconnected);
|
||||
}
|
||||
|
||||
private Task OnLoadedConfig(object sender, ConfigEventArgs e)
|
||||
{
|
||||
Task.Run(async () =>
|
||||
@@ -120,9 +198,10 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
return e.InvokeNext();
|
||||
}
|
||||
|
||||
private Task OnTcpDisconnected(TClient client, DisconnectEventArgs e)
|
||||
private async Task OnTcpDisconnected(TClient client, DisconnectEventArgs e)
|
||||
{
|
||||
Task.Run(async () =>
|
||||
await e.InvokeNext();
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
if (e.Manual)
|
||||
{
|
||||
@@ -137,84 +216,6 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return e.InvokeNext();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 每个周期可执行的委托。返回值为True标识客户端存活。返回False,表示失活,立即重连。返回null时,表示跳过此次检验。
|
||||
/// </summary>
|
||||
/// <param name="actionForCheck"></param>
|
||||
/// <returns></returns>
|
||||
public ReconnectionPlugin<TClient> SetActionForCheck(Func<TClient, int, Task<bool?>> actionForCheck)
|
||||
{
|
||||
this.ActionForCheck = actionForCheck;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 每个周期可执行的委托。返回值为True标识客户端存活。返回False,表示失活,立即重连。返回null时,表示跳过此次检验。
|
||||
/// </summary>
|
||||
/// <param name="actionForCheck"></param>
|
||||
/// <returns></returns>
|
||||
public ReconnectionPlugin<TClient> SetActionForCheck(Func<TClient, int, bool?> actionForCheck)
|
||||
{
|
||||
this.ActionForCheck = async (c, i) =>
|
||||
{
|
||||
await EasyTask.CompletedTask;
|
||||
return actionForCheck.Invoke(c, i);
|
||||
};
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置连接动作
|
||||
/// </summary>
|
||||
/// <param name="tryConnect"></param>
|
||||
/// <returns>无论如何,只要返回True,则结束本轮尝试</returns>
|
||||
public ReconnectionPlugin<TClient> SetConnectAction(Func<TClient, Task<bool>> tryConnect)
|
||||
{
|
||||
this.ActionForConnect = tryConnect;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置连接动作
|
||||
/// </summary>
|
||||
/// <param name="tryConnect"></param>
|
||||
/// <returns>无论如何,只要返回True,则结束本轮尝试</returns>
|
||||
public ReconnectionPlugin<TClient> SetConnectAction(Func<TClient, bool> tryConnect)
|
||||
{
|
||||
this.ActionForConnect = async (c) =>
|
||||
{
|
||||
await EasyTask.CompletedTask;
|
||||
return tryConnect.Invoke(c);
|
||||
};
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检验时间间隔
|
||||
/// </summary>
|
||||
/// <param name="tick"></param>
|
||||
/// <returns></returns>
|
||||
public ReconnectionPlugin<TClient> SetTick(TimeSpan tick)
|
||||
{
|
||||
this.Tick = tick;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 使用轮询保持活性。
|
||||
/// </summary>
|
||||
public ReconnectionPlugin<TClient> UsePolling()
|
||||
{
|
||||
this.ActionForCheck = (client, failCount) =>
|
||||
{
|
||||
return Task.FromResult(client?.Online);
|
||||
};
|
||||
this.m_polling = true;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
@@ -86,11 +86,11 @@ namespace ThingsGateway.Foundation.WebApi
|
||||
break;
|
||||
}
|
||||
|
||||
this.PluginsManager.Raise(nameof(IWebApiPlugin.OnRequest), this, new WebApiEventArgs(request, default));
|
||||
this.PluginsManager?.Raise(nameof(IWebApiPlugin.OnRequest), this, new WebApiEventArgs(request, default));
|
||||
|
||||
var response = this.RequestContent(request, false, invokeOption.Timeout, invokeOption.Token);
|
||||
|
||||
this.PluginsManager.Raise(nameof(IWebApiPlugin.OnResponse), this, new WebApiEventArgs(request, response));
|
||||
this.PluginsManager?.Raise(nameof(IWebApiPlugin.OnResponse), this, new WebApiEventArgs(request, response));
|
||||
|
||||
if (invokeOption.FeedbackType != FeedbackType.WaitInvoke)
|
||||
{
|
||||
@@ -152,9 +152,9 @@ namespace ThingsGateway.Foundation.WebApi
|
||||
break;
|
||||
}
|
||||
|
||||
this.PluginsManager.Raise(nameof(IWebApiPlugin.OnRequest), this, new WebApiEventArgs(request, default));
|
||||
this.PluginsManager?.Raise(nameof(IWebApiPlugin.OnRequest), this, new WebApiEventArgs(request, default));
|
||||
var response = this.RequestContent(request, false, invokeOption.Timeout, invokeOption.Token);
|
||||
this.PluginsManager.Raise(nameof(IWebApiPlugin.OnResponse), this, new WebApiEventArgs(request, response));
|
||||
this.PluginsManager?.Raise(nameof(IWebApiPlugin.OnResponse), this, new WebApiEventArgs(request, response));
|
||||
|
||||
if (invokeOption.FeedbackType != FeedbackType.WaitInvoke)
|
||||
{
|
||||
@@ -188,21 +188,133 @@ namespace ThingsGateway.Foundation.WebApi
|
||||
}
|
||||
|
||||
///<inheritdoc/>
|
||||
public Task InvokeAsync(string invokeKey, IInvokeOption invokeOption, params object[] parameters)
|
||||
public async Task InvokeAsync(string invokeKey, IInvokeOption invokeOption, params object[] parameters)
|
||||
{
|
||||
return Task.Run(() =>
|
||||
var strs = invokeKey.Split(':');
|
||||
if (strs.Length != 2)
|
||||
{
|
||||
this.Invoke(invokeKey, invokeOption, parameters);
|
||||
});
|
||||
throw new RpcException("不是有效的url请求。");
|
||||
}
|
||||
if (invokeOption == default)
|
||||
{
|
||||
invokeOption = InvokeOption.WaitInvoke;
|
||||
}
|
||||
|
||||
var request = new HttpRequest();
|
||||
|
||||
switch (strs[0])
|
||||
{
|
||||
case "GET":
|
||||
{
|
||||
request.InitHeaders()
|
||||
.SetHost(this.RemoteIPHost.Host)
|
||||
.SetUrl(strs[1].Format(parameters))
|
||||
.AsGet();
|
||||
break;
|
||||
}
|
||||
case "POST":
|
||||
{
|
||||
request.InitHeaders()
|
||||
.SetHost(this.RemoteIPHost.Host)
|
||||
.SetUrl(strs[1].Format(parameters))
|
||||
.AsPost();
|
||||
if (parameters.Length > 0)
|
||||
{
|
||||
request.FromJson(SerializeConvert.ToJsonString(parameters[parameters.Length - 1]));
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
await this.PluginsManager.RaiseAsync(nameof(IWebApiPlugin.OnRequest), this, new WebApiEventArgs(request, default));
|
||||
var response = await this.RequestContentAsync(request, false, invokeOption.Timeout, invokeOption.Token);
|
||||
await this.PluginsManager.RaiseAsync(nameof(IWebApiPlugin.OnResponse), this, new WebApiEventArgs(request, response));
|
||||
|
||||
if (invokeOption.FeedbackType != FeedbackType.WaitInvoke)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (response.StatusCode == 200)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else if (response.StatusCode == 422)
|
||||
{
|
||||
throw new RpcException(SerializeConvert.FromJsonString<ActionResult>(response.GetBody()).Message);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RpcException(response.StatusMessage);
|
||||
}
|
||||
}
|
||||
|
||||
///<inheritdoc/>
|
||||
public Task<object> InvokeAsync(Type returnType, string invokeKey, IInvokeOption invokeOption, params object[] parameters)
|
||||
public async Task<object> InvokeAsync(Type returnType, string invokeKey, IInvokeOption invokeOption, params object[] parameters)
|
||||
{
|
||||
return Task.Run(() =>
|
||||
var strs = invokeKey.Split(':');
|
||||
if (strs.Length != 2)
|
||||
{
|
||||
return this.Invoke(returnType, invokeKey, invokeOption, parameters);
|
||||
});
|
||||
throw new RpcException("不是有效的url请求。");
|
||||
}
|
||||
if (invokeOption == default)
|
||||
{
|
||||
invokeOption = InvokeOption.WaitInvoke;
|
||||
}
|
||||
|
||||
var request = new HttpRequest();
|
||||
|
||||
switch (strs[0])
|
||||
{
|
||||
case "GET":
|
||||
{
|
||||
request.InitHeaders()
|
||||
.SetHost(this.RemoteIPHost.Host)
|
||||
.SetUrl(strs[1].Format(parameters))
|
||||
.AsGet();
|
||||
break;
|
||||
}
|
||||
case "POST":
|
||||
{
|
||||
request.InitHeaders()
|
||||
.SetHost(this.RemoteIPHost.Host)
|
||||
.SetUrl(strs[1].Format(parameters))
|
||||
.AsPost();
|
||||
if (parameters.Length > 0)
|
||||
{
|
||||
request.FromJson(SerializeConvert.ToJsonString(parameters[parameters.Length - 1]));
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
await this.PluginsManager.RaiseAsync(nameof(IWebApiPlugin.OnRequest), this, new WebApiEventArgs(request, default));
|
||||
|
||||
var response = await this.RequestContentAsync(request, false, invokeOption.Timeout, invokeOption.Token);
|
||||
|
||||
await this.PluginsManager.RaiseAsync(nameof(IWebApiPlugin.OnResponse), this, new WebApiEventArgs(request, response));
|
||||
|
||||
if (invokeOption.FeedbackType != FeedbackType.WaitInvoke)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
if (response.StatusCode == 200)
|
||||
{
|
||||
return this.StringConverter.ConvertFrom(response.GetBody(), returnType);
|
||||
}
|
||||
else if (response.StatusCode == 422)
|
||||
{
|
||||
throw new RpcException(SerializeConvert.FromJsonString<ActionResult>(response.GetBody()).Message);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RpcException(response.StatusMessage);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Rpc调用
|
||||
|
@@ -85,7 +85,7 @@ namespace ThingsGateway.Foundation.WebApi
|
||||
break;
|
||||
}
|
||||
|
||||
this.PluginsManager.Raise(nameof(IWebApiPlugin.OnRequest), this, new WebApiEventArgs(request, default));
|
||||
this.PluginsManager?.Raise(nameof(IWebApiPlugin.OnRequest), this, new WebApiEventArgs(request, default));
|
||||
|
||||
using (var tokenSource = new CancellationTokenSource(invokeOption.Timeout))
|
||||
{
|
||||
@@ -95,7 +95,7 @@ namespace ThingsGateway.Foundation.WebApi
|
||||
}
|
||||
var response = this.HttpClient.SendAsync(request, tokenSource.Token).GetAwaiter().GetResult();
|
||||
|
||||
this.PluginsManager.Raise(nameof(IWebApiPlugin.OnResponse), this, new WebApiEventArgs(request, response));
|
||||
this.PluginsManager?.Raise(nameof(IWebApiPlugin.OnResponse), this, new WebApiEventArgs(request, response));
|
||||
|
||||
if (invokeOption.FeedbackType != FeedbackType.WaitInvoke)
|
||||
{
|
||||
@@ -155,7 +155,7 @@ namespace ThingsGateway.Foundation.WebApi
|
||||
break;
|
||||
}
|
||||
|
||||
this.PluginsManager.Raise(nameof(IWebApiPlugin.OnRequest), this, new WebApiEventArgs(request, default));
|
||||
this.PluginsManager?.Raise(nameof(IWebApiPlugin.OnRequest), this, new WebApiEventArgs(request, default));
|
||||
|
||||
using (var tokenSource = new CancellationTokenSource(invokeOption.Timeout))
|
||||
{
|
||||
@@ -165,7 +165,7 @@ namespace ThingsGateway.Foundation.WebApi
|
||||
}
|
||||
var response = this.HttpClient.SendAsync(request, tokenSource.Token).GetAwaiter().GetResult();
|
||||
|
||||
this.PluginsManager.Raise(nameof(IWebApiPlugin.OnResponse), this, new WebApiEventArgs(request, response));
|
||||
this.PluginsManager?.Raise(nameof(IWebApiPlugin.OnResponse), this, new WebApiEventArgs(request, response));
|
||||
|
||||
if (invokeOption.FeedbackType != FeedbackType.WaitInvoke)
|
||||
{
|
||||
@@ -324,9 +324,10 @@ namespace ThingsGateway.Foundation.WebApi
|
||||
return default;
|
||||
}
|
||||
|
||||
var str = await response.Content.ReadAsStringAsync();
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
return this.StringConverter.ConvertFrom(await response.Content.ReadAsStringAsync(), returnType);
|
||||
return this.StringConverter.ConvertFrom(str, returnType);
|
||||
}
|
||||
else if ((int)response.StatusCode == 422)
|
||||
{
|
||||
@@ -334,7 +335,7 @@ namespace ThingsGateway.Foundation.WebApi
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RpcException(response.ReasonPhrase);
|
||||
throw new RpcException(str);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<Version>3.0.0.28</Version>
|
||||
<Version>3.0.1.0</Version>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
|
||||
|
@@ -9,6 +9,7 @@
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace ThingsGateway.Plugin.Kafka;
|
||||
|
||||
/// <summary>
|
||||
|
@@ -9,6 +9,7 @@
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace ThingsGateway.Plugin.Kafka;
|
||||
|
||||
/// <summary>
|
||||
|
@@ -48,10 +48,9 @@ public partial class OPCUAServer
|
||||
else
|
||||
{
|
||||
var message = formatter(state, exception);
|
||||
_log.Log((Foundation.Core.LogLevel)(byte)logLevel, state, message, exception);
|
||||
if (logLevel > Microsoft.Extensions.Logging.LogLevel.Information)
|
||||
if (logLevel > Microsoft.Extensions.Logging.LogLevel.Warning)
|
||||
{
|
||||
|
||||
_log.Log((Foundation.Core.LogLevel)(byte)logLevel, state, message, exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -113,18 +113,13 @@ public abstract class Siemens : CollectBase
|
||||
return new(await _plc?.WriteAsync(address, value, cancellationToken));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
_plc?.Disconnect();
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override async Task<OperResult<byte[]>> ReadAsync(string address, int length, CancellationToken cancellationToken)
|
||||
{
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user