Compare commits

...

11 Commits

Author SHA1 Message Date
Kimdiego2098
1c52be8b47 添加停止线程等待时间 2023-11-16 22:32:22 +08:00
Kimdiego2098
bcd82055ca s7握手失败后,手动关闭连接 2023-11-11 10:26:05 +08:00
Kimdiego2098
c47d95d170 fix:修复线程阻塞检测触发重启时,后台变量列表不再刷新的问题! 2023-11-10 09:00:50 +08:00
Kimdiego2098
3e62f1ad51 历史数据上传成功后,才上传缓存数据 2023-11-09 18:55:56 +08:00
Kimdiego2098
8dcae973ef update 2023-11-08 16:19:46 +08:00
Kimdiego2098
4cf35f7294 发布3.0.1版本 2023-11-03 11:32:13 +08:00
Kimdiego2098
94c77d151b update touchsocket 2023-11-03 11:27:12 +08:00
Kimdiego2098
7f600e2b4b update touchsocket 2023-11-03 11:19:26 +08:00
Kimdiego2098
c809d0ba87 不存在插件时,报错内容优化 2023-11-01 14:51:08 +08:00
Kimdiego2098
50f038ec89 update webapiClient 2023-11-01 14:21:53 +08:00
Kimdiego2098
9199a255a2 调整Timeout属性为int数据类型 2023-10-31 23:49:46 +08:00
114 changed files with 2260 additions and 2099 deletions

View File

@@ -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>

View File

@@ -10,7 +10,6 @@
//------------------------------------------------------------------------------
#endregion
using System.Drawing;
namespace ThingsGateway.Foundation.Demo.Winform

View File

@@ -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

View File

@@ -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
{

View File

@@ -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>

View File

@@ -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>

View File

@@ -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);

View File

@@ -207,7 +207,7 @@ public interface IReadWrite : IDisposable
/// <summary>
/// 读写超时时间
/// </summary>
ushort TimeOut { get; set; }
int TimeOut { get; set; }
/// <summary>
/// 一个寄存器所占的字节长度

View File

@@ -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;

View File

@@ -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
}

View File

@@ -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; }
}
}

View File

@@ -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; }
}
}

View File

@@ -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>
{
}
}

View File

@@ -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>
{
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}
}

View File

@@ -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();
}
}
}

View File

@@ -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"/>

View File

@@ -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;
}

View File

@@ -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);
}
}
}
}
}

View File

@@ -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();
}
}
}
}

View File

@@ -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>

View File

@@ -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);
}
}

View File

@@ -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>

View File

@@ -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);
}
}

View File

@@ -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();
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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();
}
}

View File

@@ -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)

View File

@@ -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

View File

@@ -28,7 +28,7 @@ namespace ThingsGateway.Foundation.Dmtp
/// <summary>
/// IWebSocketDmtpClient
/// </summary>
public interface IWebSocketDmtpClient : IWebSocketDmtpClientBase
public interface IWebSocketDmtpClient : IWebSocketDmtpClientBase, ISetupConfigObject
{
/// <summary>
/// 异步连接

View File

@@ -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; }
}
}

View File

@@ -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));
}
}

View File

@@ -10,9 +10,6 @@
//------------------------------------------------------------------------------
#endregion
namespace ThingsGateway.Foundation.Dmtp
{
/// <summary>

View File

@@ -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
}
}

View File

@@ -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:

View File

@@ -22,6 +22,7 @@
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using System.Text;
using System.Web;

View File

@@ -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();
}
}
}
}

View File

@@ -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>

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}

View File

@@ -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");

View File

@@ -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>
{
}
}

View File

@@ -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>
{
}
}

View File

@@ -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>

View File

@@ -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>
{
}
}

View File

@@ -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>
{
}
}

View File

@@ -114,6 +114,7 @@ namespace ThingsGateway.Foundation.Http
};
return this;
}
/// <inheritdoc/>
public async Task OnHttpRequest(IHttpSocketClient client, HttpContextEventArgs e)
{

View File

@@ -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)
{

View File

@@ -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;
}
}
}

View File

@@ -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();
}
}
}

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -32,7 +32,7 @@ namespace ThingsGateway.Foundation.Http.WebSockets
public class WebSocketConnectException : Exception
{
/// <summary>
///构造函数
/// WebSocket连接异常
/// </summary>
/// <param name="mes"></param>
/// <param name="context"></param>

View File

@@ -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>

View File

@@ -22,6 +22,7 @@
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using ThingsGateway.Foundation.Http.WebSockets;
namespace ThingsGateway.Foundation.Sockets

View File

@@ -22,6 +22,7 @@
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using ThingsGateway.Foundation.Http.WebSockets;
namespace ThingsGateway.Foundation.Core

View File

@@ -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>

View File

@@ -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);
}
}

View File

@@ -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);

View File

@@ -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();
}
}
}

View File

@@ -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);
}

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>();

View File

@@ -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>

View File

@@ -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;
}

View File

@@ -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);
}
}

View File

@@ -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>();

View File

@@ -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)
{

View File

@@ -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);
}
}

View File

@@ -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);

View File

@@ -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>

View File

@@ -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)

View File

@@ -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
}
}

View File

@@ -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
}
}

View File

@@ -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
}
}

View File

@@ -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; }
}
}

View File

@@ -28,7 +28,7 @@ namespace ThingsGateway.Foundation.Sockets
/// <summary>
/// 终端接口
/// </summary>
public interface IClient : IDependencyObject, IDisposable, ISocket
public interface IClient : IDependencyObject, IDisposable, ILoggerObject
{
/// <summary>
/// 获取一个同步数据接收器

View File

@@ -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);
}
}

View File

@@ -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; }
}
}

View File

@@ -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>

View File

@@ -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);
}
}

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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;
}
}
}

View File

@@ -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调用

View File

@@ -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);
}
}
}

View File

@@ -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>

View File

@@ -9,6 +9,7 @@
// QQ群605534569
//------------------------------------------------------------------------------
#endregion
namespace ThingsGateway.Plugin.Kafka;
/// <summary>

View File

@@ -9,6 +9,7 @@
// QQ群605534569
//------------------------------------------------------------------------------
#endregion
namespace ThingsGateway.Plugin.Kafka;
/// <summary>

View File

@@ -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);
}
}
}

View File

@@ -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