From b3921b1037de270e5f169e2984e445641adf5a3b Mon Sep 17 00:00:00 2001
From: Kimdiego2098 <2248356998@qq.com>
Date: Fri, 13 Oct 2023 19:16:12 +0800
Subject: [PATCH] update touchsocket
---
framework/Demo/Directory.Build.props | 2 +-
framework/Foundation/Directory.Build.props | 8 +-
.../DLT645/PackHelper.cs | 1 -
...hingsGateway.Foundation.Adapter.DLT645.xml | 442 -
.../ModbusSerialServer/ModbusSerialServer.cs | 11 +-
.../Modbus/ModbusTcpDtu/ModbusTcpDtu.cs | 13 +-
.../Modbus/ModbusTcpServer/ModbusTcpServer.cs | 11 +-
...ngsGateway.Foundation.Adapter.OPCDA.csproj | 5 +
...ThingsGateway.Foundation.Adapter.OPCDA.xml | 579 -
...ThingsGateway.Foundation.Adapter.OPCUA.xml | 468 -
.../Siemens/DateTime.cs | 1 -
.../Siemens/Helper/PackHelper.cs | 1 -
.../Siemens/SiemensS7PLC.cs | 20 +-
...ingsGateway.Foundation.Adapter.Siemens.xml | 336 -
.../ReadWriteDevicesSerialSessionBase.cs | 50 +-
.../ReadWriteDevicesTcpClientBase.cs | 32 +-
.../ReadWriteDevicesTcpServerBase.cs | 39 +-
.../ReadWriteDevicesUdpSessionBase.cs | 10 +-
.../ReadWriteDevicesTcpDataHandleAdapter.cs | 21 +
.../ReadWriteDevicesUdpDataHandleAdapter.cs | 5 -
.../ThingsGateway.Foundation.csproj | 15 +
.../Core/Common/DisposableObject.cs | 2 +-
.../Core/DataAdapter/DataHandlingAdapter.cs | 13 -
.../DataAdapter/NormalDataHandlingAdapter.cs | 18 +
.../Package/FixedHeaderPackageAdapter.cs | 125 +
.../Package/FixedSizePackageAdapter.cs | 64 +
.../Package/TerminatorPackageAdapter.cs | 59 +
.../DataAdapter/SingleStreamAdapterOption.cs | 15 +-
.../SingleStreamDataHandlingAdapter.cs | 147 +-
.../Test/SingleStreamDataAdapterTester.cs | 12 +-
.../TouchSocket/Core/Dependency/Container.cs | 61 +-
.../Core/Dependency/ContainerExtension.cs | 63 +-
.../TouchSocket/Core/Dependency/IContainer.cs | 3 +-
.../Core/Dependency/ManualContainer.cs | 7 +-
.../Core/Extensions/TaskExtension.cs | 20 +
.../TouchSocket/Core/Plugins/IPlugin.cs | 8 -
.../TouchSocket/Core/Plugins/PluginBase.cs | 3 -
.../Core/{Common => Threading}/Locker.cs | 0
.../Dmtp/Components/Http/HttpDmtpClient.cs | 16 +-
.../Dmtp/Components/Http/HttpDmtpService.cs | 4 +-
.../Components/Http/HttpDmtpSocketClient.cs | 45 +-
.../Dmtp/Components/TCP/TcpDmtpClient.cs | 51 +-
.../Dmtp/Components/TCP/TcpDmtpService.cs | 4 +-
.../Components/TCP/TcpDmtpSocketClient.cs | 37 +-
.../Dmtp/Components/Udp/UdpDmtp.cs | 8 +-
.../WebSocket/WebSocketDmtpClient.cs | 45 +-
.../Actor/DmtpFileTransferActor.cs | 2 +-
.../TouchSocket/Http/Components/HttpClient.cs | 15 +-
.../Http/Components/HttpClientSlim.cs | 12 +-
.../Http/Components/HttpSocketClient.cs | 19 +-
.../Plugins/Interfaces/IHttpDeletePlugin.cs | 37 -
.../Http/Plugins/Interfaces/IHttpGetPlugin.cs | 37 -
.../Http/Plugins/Interfaces/IHttpPlugin.cs | 3 +-
.../Plugins/Interfaces/IHttpPostPlugin.cs | 37 -
.../WebSockets/Common/InternalWebSocket.cs | 16 +-
.../Common/WebSocketReceiveResult.cs | 5 +
.../WebSockets/Components/WebSocketClient.cs | 60 +-
.../WebSocketDataHandlingAdapter.cs | 41 +-
.../Http/WebSockets/DelegateCollection.cs | 2 +-
...ensions.cs => WebSocketClientExtension.cs} | 2 +-
.../WebSocketConfigExtension.cs} | 2 +-
...ions.cs => WebSocketDataFrameExtension.cs} | 2 +-
...ensions.cs => WebSocketServerExtension.cs} | 12 +-
.../Http/WebSockets/Interface/IWebSocket.cs | 9 +-
.../WebSockets/Plugins/WebSocketFeature.cs | 26 +-
.../TouchSocket/Rpc/Enum/CodeGeneratorFlag.cs | 6 -
.../EventArgs/SerialConnectingEventArgs.cs | 2 +-
.../SerialPort/Interface/ISerial.cs | 16 +-
.../Interface/ISerialSessionBase.cs | 4 +-
.../SerialPort/SerialPort/BaseSerial.cs | 14 +-
.../SerialPort/SerialPort/SerialCore.cs | 396 +
.../SerialPort/SerialPort/SerialSession.cs | 624 +-
.../TouchSocket/Socket/BaseSocket.cs | 15 +-
.../Socket/Common/Options/TcpListenOption.cs | 5 -
.../Socket/Components/Core/TcpCore.cs | 1009 +-
.../Socket/Components/NAT/NATService.cs | 22 +-
.../Socket/Components/NAT/NATSocketClient.cs | 14 +-
.../Socket/Components/Tcp/SocketClient.cs | 720 +-
.../Socket/Components/Tcp/TcpClient.cs | 1987 ++-
.../Socket/Components/Tcp/TcpService.cs | 119 +-
.../Socket/Components/Tcp/TcpServiceBase.cs | 72 +-
.../Socket/Components/Udp/UdpSession.cs | 174 +-
.../Udp/NormalUdpDataHandlingAdapter.cs | 9 -
.../DataAdapter/Udp/UdpPackageAdapter.cs | 9 -
.../TouchSocket/Socket/DelegateCollection.cs | 104 +-
.../TouchSocket/Socket/Enum/ReceiveType.cs | 48 -
.../Socket/Extensions/ClientExtension.cs | 31 +-
.../Socket/Extensions/ServiceExtension.cs | 28 +-
.../Extensions/TouchSocketConfigExtension.cs | 22 -
.../TouchSocket/Socket/Interface/IClient.cs | 14 +-
.../Socket/Interface/ISender/ISender.cs | 3 -
.../Socket/Interface/ITcpClient.cs | 9 +-
.../Socket/Interface/ITcpClientBase.cs | 16 +-
.../Interfaces/ITcpDisconnectingPlugin.cs | 3 -
.../Receiver/IReceiver.cs} | 31 +-
.../TouchSocket/Socket/Receiver/Receiver.cs | 91 +
.../Socket/Receiver/ReceiverResult.cs | 56 +
.../Socket/WaitingClient/IWaitingClient.cs | 2 +-
.../Socket/WaitingClient/ResponsedData.cs | 10 +-
.../Socket/WaitingClient/WaitingClient.cs | 556 +-
.../WaitingClient/WaitingClientExtension.cs | 63 +-
.../Socket/WaitingClient/WaitingOptions.cs | 31 +-
.../SwaggerDescriptionAttribute.cs} | 30 +-
.../WebApi.Swagger/Common/OpenApiComponent.cs | 22 +
.../WebApi.Swagger/Common/OpenApiContent.cs | 22 +
.../WebApi.Swagger/Common/OpenApiDataTypes.cs | 80 +
.../WebApi.Swagger/Common/OpenApiInfo.cs | 25 +
.../WebApi.Swagger/Common/OpenApiParameter.cs | 28 +
.../WebApi.Swagger/Common/OpenApiPath.cs | 18 +
.../WebApi.Swagger/Common/OpenApiPathValue.cs | 40 +
.../WebApi.Swagger/Common/OpenApiProperty.cs | 34 +
.../Common/OpenApiRequestBody.cs | 25 +
.../WebApi.Swagger/Common/OpenApiResponse.cs | 25 +
.../WebApi.Swagger/Common/OpenApiRoot.cs | 31 +
.../WebApi.Swagger/Common/OpenApiSchema.cs | 37 +
.../Extensions/OpenApiExtension.cs | 40 +
.../SwaggerPluginsManagerExtension.cs} | 23 +-
.../OpenApiStringEnumConverter.cs | 24 +
.../WebApi.Swagger/Plugins/SwaggerPlugin.cs | 701 +
.../WebApi.Swagger/api/favicon-16x16.png | Bin 0 -> 665 bytes
.../WebApi.Swagger/api/favicon-32x32.png | Bin 0 -> 628 bytes
.../TouchSocket/WebApi.Swagger/api/index.html | 59 +
.../WebApi.Swagger/api/oauth2-redirect.html | 75 +
.../WebApi.Swagger/api/openapi.json | 78 +
.../WebApi.Swagger/api/swagger-ui-bundle.js | 3 +
.../api/swagger-ui-es-bundle-core.js | 3 +
.../api/swagger-ui-es-bundle.js | 3 +
.../api/swagger-ui-standalone-preset.js | 3 +
.../WebApi.Swagger/api/swagger-ui.css | 11073 ++++++++++++++++
.../WebApi.Swagger/api/swagger-ui.js | 3 +
framework/Plugin/Directory.Build.props | 2 +-
.../ModbusSerialServer/ModbusSerialServer.cs | 8 +-
.../ModbusTcpServer/ModbusTcpServer.cs | 8 +-
framework/UpgradeManger/Directory.Build.props | 2 +-
.../UpgradeManger/UpgradeManger.cs | 5 +-
framework/Web/Directory.Build.props | 2 +-
.../ManageGateway/ManageGatewayConfig.cs | 1 -
.../Workers/Upgrade/UpgradeWorker.cs | 3 +-
138 files changed, 16480 insertions(+), 5630 deletions(-)
delete mode 100644 framework/Foundation/ThingsGateway.Foundation.Adapter.DLT645/ThingsGateway.Foundation.Adapter.DLT645.xml
delete mode 100644 framework/Foundation/ThingsGateway.Foundation.Adapter.OPCDA/ThingsGateway.Foundation.Adapter.OPCDA.xml
delete mode 100644 framework/Foundation/ThingsGateway.Foundation.Adapter.OPCUA/ThingsGateway.Foundation.Adapter.OPCUA.xml
delete mode 100644 framework/Foundation/ThingsGateway.Foundation.Adapter.Siemens/ThingsGateway.Foundation.Adapter.Siemens.xml
rename framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/{Common => Threading}/Locker.cs (100%)
delete mode 100644 framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/Plugins/Interfaces/IHttpDeletePlugin.cs
delete mode 100644 framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/Plugins/Interfaces/IHttpGetPlugin.cs
delete mode 100644 framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/Plugins/Interfaces/IHttpPostPlugin.cs
rename framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/WebSockets/Extensions/{WebSocketClientExtensions.cs => WebSocketClientExtension.cs} (99%)
rename framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/WebSockets/{Config/WebSocketConfigExtensions.cs => Extensions/WebSocketConfigExtension.cs} (98%)
rename framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/WebSockets/Extensions/{WebSocketDataFrameExtensions.cs => WebSocketDataFrameExtension.cs} (99%)
rename framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/WebSockets/Extensions/{WebSocketServerExtensions.cs => WebSocketServerExtension.cs} (94%)
create mode 100644 framework/Foundation/ThingsGateway.Foundation/TouchSocket/SerialPort/SerialPort/SerialCore.cs
delete mode 100644 framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Enum/ReceiveType.cs
rename framework/Foundation/ThingsGateway.Foundation/TouchSocket/{Http/Plugins/Interfaces/IHttpPutPlugin.cs => Socket/Receiver/IReceiver.cs} (51%)
create mode 100644 framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Receiver/Receiver.cs
create mode 100644 framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Receiver/ReceiverResult.cs
rename framework/Foundation/ThingsGateway.Foundation/TouchSocket/{Core/DataAdapter/Decorators/AdapterData.cs => WebApi.Swagger/Attributes/SwaggerDescriptionAttribute.cs} (61%)
create mode 100644 framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/Common/OpenApiComponent.cs
create mode 100644 framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/Common/OpenApiContent.cs
create mode 100644 framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/Common/OpenApiDataTypes.cs
create mode 100644 framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/Common/OpenApiInfo.cs
create mode 100644 framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/Common/OpenApiParameter.cs
create mode 100644 framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/Common/OpenApiPath.cs
create mode 100644 framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/Common/OpenApiPathValue.cs
create mode 100644 framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/Common/OpenApiProperty.cs
create mode 100644 framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/Common/OpenApiRequestBody.cs
create mode 100644 framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/Common/OpenApiResponse.cs
create mode 100644 framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/Common/OpenApiRoot.cs
create mode 100644 framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/Common/OpenApiSchema.cs
create mode 100644 framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/Extensions/OpenApiExtension.cs
rename framework/Foundation/ThingsGateway.Foundation/TouchSocket/{Core/DataAdapter/Decorators/SingleStreamDecorator.cs => WebApi.Swagger/Extensions/SwaggerPluginsManagerExtension.cs} (58%)
create mode 100644 framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/JsonConverters/OpenApiStringEnumConverter.cs
create mode 100644 framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/Plugins/SwaggerPlugin.cs
create mode 100644 framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/api/favicon-16x16.png
create mode 100644 framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/api/favicon-32x32.png
create mode 100644 framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/api/index.html
create mode 100644 framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/api/oauth2-redirect.html
create mode 100644 framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/api/openapi.json
create mode 100644 framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/api/swagger-ui-bundle.js
create mode 100644 framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/api/swagger-ui-es-bundle-core.js
create mode 100644 framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/api/swagger-ui-es-bundle.js
create mode 100644 framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/api/swagger-ui-standalone-preset.js
create mode 100644 framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/api/swagger-ui.css
create mode 100644 framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/api/swagger-ui.js
diff --git a/framework/Demo/Directory.Build.props b/framework/Demo/Directory.Build.props
index 20a309ed5..3ccfa4e10 100644
--- a/framework/Demo/Directory.Build.props
+++ b/framework/Demo/Directory.Build.props
@@ -1,6 +1,6 @@
- 3.0.0.7
+ 3.0.0.8
latest
net6.0;net7.0
Diego
diff --git a/framework/Foundation/Directory.Build.props b/framework/Foundation/Directory.Build.props
index d8b50c242..5d68b0ac6 100644
--- a/framework/Foundation/Directory.Build.props
+++ b/framework/Foundation/Directory.Build.props
@@ -1,6 +1,6 @@
- 3.0.0.7
+ 3.0.0.8
True
latest
net45;netstandard2.0;net6.0;net7.0
@@ -42,5 +42,9 @@
-
+
+ True
+ Embedded
+ True
+
\ No newline at end of file
diff --git a/framework/Foundation/ThingsGateway.Foundation.Adapter.DLT645/DLT645/PackHelper.cs b/framework/Foundation/ThingsGateway.Foundation.Adapter.DLT645/DLT645/PackHelper.cs
index a4a8a9c57..36cc22f97 100644
--- a/framework/Foundation/ThingsGateway.Foundation.Adapter.DLT645/DLT645/PackHelper.cs
+++ b/framework/Foundation/ThingsGateway.Foundation.Adapter.DLT645/DLT645/PackHelper.cs
@@ -10,7 +10,6 @@
//------------------------------------------------------------------------------
#endregion
-
namespace ThingsGateway.Foundation.Adapter.DLT645;
internal static class PackHelper
diff --git a/framework/Foundation/ThingsGateway.Foundation.Adapter.DLT645/ThingsGateway.Foundation.Adapter.DLT645.xml b/framework/Foundation/ThingsGateway.Foundation.Adapter.DLT645/ThingsGateway.Foundation.Adapter.DLT645.xml
deleted file mode 100644
index 20cd4d39e..000000000
--- a/framework/Foundation/ThingsGateway.Foundation.Adapter.DLT645/ThingsGateway.Foundation.Adapter.DLT645.xml
+++ /dev/null
@@ -1,442 +0,0 @@
-
-
-
- ThingsGateway.Foundation.Adapter.DLT645
-
-
-
-
- 解析参数
-
-
-
-
- 解析长度
-
-
-
-
- 小数位
-
-
-
-
- 有符号解析
-
-
-
-
- 获取返回的解析信息
-
-
-
-
-
-
- 获取DLT645报文
-
-
-
-
- DLT645_2007
-
-
-
-
- DLT645_2007
-
-
-
-
-
- 增加FE FE FE FE的报文头部
-
-
-
-
- 写入需操作员代码
-
-
-
-
- 写入密码
-
-
-
-
- 通讯地址BCD码,一般应该是12个字符
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 广播校时
-
-
-
-
-
-
-
- 冻结
-
-
-
-
-
-
-
- 读取通信地址
-
-
-
-
-
-
- 修改波特率
-
-
-
-
-
-
-
- 更新通信地址
-
-
-
-
-
-
-
- 修改密码
-
-
-
-
-
-
-
-
-
- 控制码
-
-
-
-
- 读数据
-
-
-
-
- 读后续数据
-
-
-
-
- 读站号
-
-
-
-
- 写数据
-
-
-
-
- 写站号
-
-
-
-
- 广播校时
-
-
-
-
- 冻结
-
-
-
-
- 更新波特率
-
-
-
-
- 更新密码
-
-
-
-
- DLT645_2007Address
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 数据标识
-
-
-
-
- 反转解析
-
-
-
-
- 站号信息
-
-
-
-
-
-
-
- 解析地址
-
-
-
-
-
-
-
-
-
-
- DLT645_2007
-
-
-
-
- DLT645_2007
-
-
-
-
- DLT645协议转换double
-
- 带数据项标识
-
-
-
-
-
-
-
-
-
-
-
- DLT645_2007DataHandleAdapter
-
-
-
-
- 增加FE FE FE FE的报文头部
-
-
-
-
-
-
-
-
-
-
-
-
-
- DLT645_2007
-
-
-
-
- DLT645_2007
-
-
-
-
-
- 增加FE FE FE FE的报文头部
-
-
-
-
- 写入需操作员代码
-
-
-
-
- 写入密码
-
-
-
-
- 通讯地址BCD码,一般应该是12个字符
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 广播校时
-
-
-
-
-
-
-
- 冻结
-
-
-
-
-
-
-
- 读取通信地址
-
-
-
-
-
-
- 修改波特率
-
-
-
-
-
-
-
- 更新通信地址
-
-
-
-
-
-
-
- 修改密码
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/framework/Foundation/ThingsGateway.Foundation.Adapter.Modbus/Modbus/ModbusSerialServer/ModbusSerialServer.cs b/framework/Foundation/ThingsGateway.Foundation.Adapter.Modbus/Modbus/ModbusSerialServer/ModbusSerialServer.cs
index 72ef82039..8c35a4af6 100644
--- a/framework/Foundation/ThingsGateway.Foundation.Adapter.Modbus/Modbus/ModbusSerialServer/ModbusSerialServer.cs
+++ b/framework/Foundation/ThingsGateway.Foundation.Adapter.Modbus/Modbus/ModbusSerialServer/ModbusSerialServer.cs
@@ -24,7 +24,7 @@ public class ModbusSerialServer : ReadWriteDevicesSerialSessionBase
///
/// 接收外部写入时,传出变量地址/写入字节组/转换规则/客户端
///
- public Func WriteData;
+ public Func> WriteData;
///
/// 继电器
@@ -267,12 +267,13 @@ public class ModbusSerialServer : ReadWriteDevicesSerialSessionBase
{
return Task.FromResult(Write(address, value));
}
+
///
- protected override void Received(ByteBlock byteBlock, IRequestInfo requestInfo)
+ protected override async Task Received(SerialSession client, ReceivedDataEventArgs e)
{
try
{
-
+ var requestInfo = e.RequestInfo;
//接收外部报文
if (requestInfo is ModbusSerialServerMessage modbusServerMessage)
{
@@ -312,7 +313,7 @@ public class ModbusSerialServer : ReadWriteDevicesSerialSessionBase
if (WriteData != null)
{
// 接收外部写入时,传出变量地址/写入字节组/转换规则/客户端
- if ((WriteData(modbusServerMessage.CurModbusAddress, modbusServerMessage.Content, ThingsGatewayBitConverter, SerialSession)).IsSuccess)
+ if ((await WriteData(modbusServerMessage.CurModbusAddress, modbusServerMessage.Content, ThingsGatewayBitConverter, SerialSession)).IsSuccess)
{
var result = Write(modbusServerMessage.CurModbusAddress.ToString(), coreData.ByteToBoolArray(modbusServerMessage.Length));
if (result.IsSuccess)
@@ -349,7 +350,7 @@ public class ModbusSerialServer : ReadWriteDevicesSerialSessionBase
if (WriteData != null)
{
- if ((WriteData(modbusServerMessage.CurModbusAddress, modbusServerMessage.Content, ThingsGatewayBitConverter, SerialSession)).IsSuccess)
+ if ((await WriteData(modbusServerMessage.CurModbusAddress, modbusServerMessage.Content, ThingsGatewayBitConverter, SerialSession)).IsSuccess)
{
var result = Write(modbusServerMessage.CurModbusAddress.ToString(), coreData);
if (result.IsSuccess)
diff --git a/framework/Foundation/ThingsGateway.Foundation.Adapter.Modbus/Modbus/ModbusTcpDtu/ModbusTcpDtu.cs b/framework/Foundation/ThingsGateway.Foundation.Adapter.Modbus/Modbus/ModbusTcpDtu/ModbusTcpDtu.cs
index d584581ef..7e6740455 100644
--- a/framework/Foundation/ThingsGateway.Foundation.Adapter.Modbus/Modbus/ModbusTcpDtu/ModbusTcpDtu.cs
+++ b/framework/Foundation/ThingsGateway.Foundation.Adapter.Modbus/Modbus/ModbusTcpDtu/ModbusTcpDtu.cs
@@ -84,15 +84,6 @@ public class ModbusTcpDtu : ReadWriteDevicesTcpServerBase
return new OperResult(ex);
}
}
- ///
- ///
- ///
- ///
- ///
- protected override void Connecting(SocketClient client, ConnectingEventArgs e)
- {
- Logger?.Debug(client.IP + ":" + client.Port + "正在连接");
- }
///
public override void SetDataAdapter(object socketClient = null)
@@ -195,7 +186,7 @@ public class ModbusTcpDtu : ReadWriteDevicesTcpServerBase
var item = commandResult.Content;
if (FrameTime != 0)
Thread.Sleep(FrameTime);
- var WaitingClientEx = client.GetWaitingClientEx(new() { BreakTrigger = true });
+ var WaitingClientEx = client.GetWaitingClient(new() { ThrowBreakException = true });
var result = WaitingClientEx.SendThenResponse(item, TimeOut, cancellationToken);
return (MessageBase)result.RequestInfo;
}
@@ -222,7 +213,7 @@ public class ModbusTcpDtu : ReadWriteDevicesTcpServerBase
var item = commandResult.Content;
await Task.Delay(FrameTime, cancellationToken);
- var WaitingClientEx = client.GetWaitingClientEx(new() { BreakTrigger = true });
+ var WaitingClientEx = client.GetWaitingClient(new() { ThrowBreakException = true });
var result = await WaitingClientEx.SendThenResponseAsync(item, TimeOut, cancellationToken);
return (MessageBase)result.RequestInfo;
}
diff --git a/framework/Foundation/ThingsGateway.Foundation.Adapter.Modbus/Modbus/ModbusTcpServer/ModbusTcpServer.cs b/framework/Foundation/ThingsGateway.Foundation.Adapter.Modbus/Modbus/ModbusTcpServer/ModbusTcpServer.cs
index 94ab2e8b1..8e1626837 100644
--- a/framework/Foundation/ThingsGateway.Foundation.Adapter.Modbus/Modbus/ModbusTcpServer/ModbusTcpServer.cs
+++ b/framework/Foundation/ThingsGateway.Foundation.Adapter.Modbus/Modbus/ModbusTcpServer/ModbusTcpServer.cs
@@ -25,7 +25,7 @@ public class ModbusTcpServer : ReadWriteDevicesTcpServerBase
///
/// 接收外部写入时,传出变量地址/写入字节组/转换规则/客户端
///
- public Func WriteData;
+ public Func> WriteData;
///
/// 继电器
@@ -284,12 +284,13 @@ public class ModbusTcpServer : ReadWriteDevicesTcpServerBase
{
return Task.FromResult(Write(address, value));
}
+
///
- protected override void Received(SocketClient client, IRequestInfo requestInfo)
+ protected override async Task Received(SocketClient client, ReceivedDataEventArgs e)
{
try
{
-
+ var requestInfo = e.RequestInfo;
//接收外部报文
if (requestInfo is ModbusTcpServerMessage modbusServerMessage)
{
@@ -330,7 +331,7 @@ public class ModbusTcpServer : ReadWriteDevicesTcpServerBase
if (WriteData != null)
{
// 接收外部写入时,传出变量地址/写入字节组/转换规则/客户端
- if ((WriteData(modbusServerMessage.CurModbusAddress, modbusServerMessage.Content, ThingsGatewayBitConverter, client)).IsSuccess)
+ if ((await WriteData(modbusServerMessage.CurModbusAddress, modbusServerMessage.Content, ThingsGatewayBitConverter, client)).IsSuccess)
{
var result = Write(modbusServerMessage.CurModbusAddress.ToString(), coreData.ByteToBoolArray(modbusServerMessage.Length));
if (result.IsSuccess)
@@ -367,7 +368,7 @@ public class ModbusTcpServer : ReadWriteDevicesTcpServerBase
if (WriteData != null)
{
- if ((WriteData(modbusServerMessage.CurModbusAddress, modbusServerMessage.Content, ThingsGatewayBitConverter, client)).IsSuccess)
+ if ((await WriteData(modbusServerMessage.CurModbusAddress, modbusServerMessage.Content, ThingsGatewayBitConverter, client)).IsSuccess)
{
var result = Write(modbusServerMessage.CurModbusAddress.ToString(), coreData);
if (result.IsSuccess)
diff --git a/framework/Foundation/ThingsGateway.Foundation.Adapter.OPCDA/ThingsGateway.Foundation.Adapter.OPCDA.csproj b/framework/Foundation/ThingsGateway.Foundation.Adapter.OPCDA/ThingsGateway.Foundation.Adapter.OPCDA.csproj
index c63216103..b43726008 100644
--- a/framework/Foundation/ThingsGateway.Foundation.Adapter.OPCDA/ThingsGateway.Foundation.Adapter.OPCDA.csproj
+++ b/framework/Foundation/ThingsGateway.Foundation.Adapter.OPCDA/ThingsGateway.Foundation.Adapter.OPCDA.csproj
@@ -1,3 +1,8 @@
+
+
+ net45;netstandard2.0;net6.0;net7.0
+
+
diff --git a/framework/Foundation/ThingsGateway.Foundation.Adapter.OPCDA/ThingsGateway.Foundation.Adapter.OPCDA.xml b/framework/Foundation/ThingsGateway.Foundation.Adapter.OPCDA/ThingsGateway.Foundation.Adapter.OPCDA.xml
deleted file mode 100644
index 6e3ec486d..000000000
--- a/framework/Foundation/ThingsGateway.Foundation.Adapter.OPCDA/ThingsGateway.Foundation.Adapter.OPCDA.xml
+++ /dev/null
@@ -1,579 +0,0 @@
-
-
-
- ThingsGateway.Foundation.Adapter.OPCDA
-
-
-
-
- 移除符合条件的元素
-
-
-
-
-
-
-
- The WIN32 system default locale.
-
-
-
-
- The WIN32 user default locale.
-
-
-
-
- 创建一个COM服务器的实例。
-
-
-
-
- 指定错误消息文本检索系统。
-
-
-
-
- 初始化COM安全。
-
-
-
-
- 从枚举器读取guid。
-
-
-
-
- 从枚举器读取guid。
-
-
-
-
- 释放 COM 对象
-
-
-
-
-
- windows的filetime是从1601-1-1 00:00:00开始的,datetime是从1-1-1 00:00:00开始的
- datetime和filetime的滴答单位都是100ns(100纳秒,千万分之一秒),所以转换时只需要考虑开始时间即可
-
-
-
-
- 值变化
-
-
-
-
-
- 读取
-
-
-
-
-
- 写入
-
-
-
-
-
- 返回结果
-
-
-
-
- ID
-
-
-
-
- Quality
-
-
-
-
- TimeStamp
-
-
-
-
- Value
-
-
-
-
- 建立连接
-
-
-
-
-
- 组读取
-
-
-
-
-
- OpcItem
-
-
-
-
- OpcItem
-
-
-
-
-
- AccessPath
-
-
-
-
- Blob
-
-
-
-
- BlobSize
-
-
-
-
- ClientHandle
-
-
-
-
- active(1) or not(0)
-
-
-
-
- 数据项在opc server的完全名称
-
-
-
-
- Quality
-
-
-
-
- RunTimeDataType
-
-
-
-
- ServerHandle
-
-
-
-
- TimeStamp
-
-
-
-
- Value
-
-
-
-
-
-
-
- 获取节点
-
-
-
-
- 服务器状态
-
-
-
-
-
- ServerStatus
-
-
-
-
- CurrentTime
-
-
-
-
- LastUpdateTime
-
-
-
-
- ServerState
-
-
-
-
- StartTime
-
-
-
-
- VendorInfo
-
-
-
-
- Version
-
-
-
-
- OpcDiscovery
-
-
-
-
- GetOpcServer
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 订阅变化项
-
-
-
-
-
- OPCDAClient
-
-
-
-
- 当前保存的需订阅列表
-
-
-
-
-
-
-
-
-
-
- 数据变化事件
-
-
-
-
- 是否连接成功
-
-
-
-
- 当前配置
-
-
-
-
- 添加节点,需要在连接成功后执行
-
- 组名称/变量节点,注意每次添加的组名称不能相同
-
-
-
- 设置节点并保存,每次重连会自动添加节点
-
-
-
-
-
-
- 连接服务器
-
-
-
-
- 断开连接
-
-
-
-
- 浏览节点
-
-
-
-
-
-
- 获取服务状态
-
-
-
-
-
- 初始化设置
-
-
-
-
-
- 按OPC组读取组内变量,结果会在订阅事件中返回
-
- 组名称,值为null时读取全部组
-
-
-
-
- 移除节点
-
-
-
-
-
-
-
-
- 批量写入值
-
-
-
-
-
-
-
-
- OPCDA连接配置项
-
-
-
-
- 是否订阅
-
-
-
-
- 内部检测重连间隔/min
-
-
-
-
- 死区
-
-
-
-
- 分组大小
-
-
-
-
- OPCIP
-
-
-
-
- OPCNAME
-
-
-
-
- 订阅间隔
-
-
-
-
-
-
-
-
-
-
diff --git a/framework/Foundation/ThingsGateway.Foundation.Adapter.OPCUA/ThingsGateway.Foundation.Adapter.OPCUA.xml b/framework/Foundation/ThingsGateway.Foundation.Adapter.OPCUA/ThingsGateway.Foundation.Adapter.OPCUA.xml
deleted file mode 100644
index 7ba6d412c..000000000
--- a/framework/Foundation/ThingsGateway.Foundation.Adapter.OPCUA/ThingsGateway.Foundation.Adapter.OPCUA.xml
+++ /dev/null
@@ -1,468 +0,0 @@
-
-
-
- ThingsGateway.Foundation.Adapter.OPCUA
-
-
-
-
- 移除符合条件的元素
-
-
-
-
-
-
-
- 异步Select
-
-
-
-
-
-
-
-
-
- 辅助类
-
-
-
-
- Browses the address space and returns the references found.
-
- The session.
- The set of browse operations to perform.
- if set to true a exception will be thrown on an error.
-
- The references found. Null if an error occurred.
-
-
-
-
- Create the continuation point collection from the browse result
- collection for the BrowseNext service.
-
- The browse result collection to use.
- The collection of continuation points for the BrowseNext service.
-
-
-
- 浏览地址空间
-
-
-
-
-
-
-
-
-
-
- 浏览地址空间
-
-
-
-
-
-
-
-
-
-
- 浏览地址空间并返回指定类型的所有节点
-
-
-
-
-
-
-
-
-
- Collects the fields for the instance.
-
-
-
-
- Collects the fields for the type.
-
-
-
-
- Constructs an event object from a notification.
-
- The session.
- The monitored item that produced the notification.
- The notification.
- The known event types.
- Mapping between event types and known event types.
-
- The event object. Null if the notification is not a valid event type.
-
-
-
-
- Discovers the servers on the local machine.
-
- The configuration.
- A list of server urls.
-
-
-
- Finds the type of the event for the notification.
-
- The monitored item.
- The notification.
- The NodeId of the EventType.
-
-
-
- 指定的属性的显示文本。
-
-
-
-
- Finds the endpoint that best matches the current settings.
-
- The discovery URL.
- if set to true select an endpoint that uses security.
- The best available endpoint.
-
-
-
- 返回一组相对路径的节点id
-
-
-
-
- Collects the fields for the instance node.
-
- The session.
- The node id.
- The parent path.
- The event fields.
- The node id for the declaration of the field.
- The table of found nodes.
-
-
-
- 判断指定的select子句包含的浏览路径。
-
-
-
-
- 访问级别属性的显示文本。
-
-
-
-
- 事件通知属性的显示文本
-
-
-
-
- 扩展方法
-
-
-
-
- 解析获取DataValue
-
-
-
-
-
- 解析获取object
-
-
-
-
-
- DecodeRawData
-
-
-
-
-
- OPCUAValue解析为Jtoken
-
-
-
-
-
-
-
-
- CreateEncoder
-
-
-
-
-
- 维度
-
-
-
-
-
-
- OPCUAClient配置项
-
-
-
-
- OPCUrl
-
-
-
-
- 登录账号
-
-
-
-
- 登录密码
-
-
-
-
- 检查域
-
-
-
-
- 更新间隔
-
-
-
-
- 是否订阅
-
-
-
-
- 分组大小
-
-
-
-
- 死区
-
-
-
-
- KeepAliveInterval/ms
-
-
-
-
- 安全策略
-
-
-
-
-
-
-
- 订阅委托
-
-
-
-
-
- OPCUAClient
-
-
-
-
- 当前配置
-
-
-
-
- ProductUri
-
-
-
-
- 当前保存的变量名称列表
-
-
-
-
- 当前的变量名称/OPC变量节点
-
-
-
-
- 当前的订阅组,组名称/组
-
-
-
-
- SessionReconnectHandler
-
-
-
-
- 默认的构造函数,实例化一个新的OPC UA类
-
-
-
-
- 订阅
-
-
-
-
- 配置信息
-
-
-
-
- 连接状态
-
-
-
-
- OPCUAClient
-
-
-
-
- 当前活动会话。
-
-
-
-
- 新增订阅,需要指定订阅组名称,订阅的tag名数组
-
-
-
-
- 移除所有的订阅消息
-
-
-
-
- 移除订阅消息
-
- 组名称
-
-
-
- 浏览一个节点的引用
-
- 节点值
- 引用节点描述
-
-
-
- 调用服务器的方法
-
- 方法的父节点tag
- 方法的节点tag
- 传递的参数
- 输出的结果值
-
-
-
- 读取历史数据
-
- 节点的索引
- 开始时间
- 结束时间
- 读取的个数
- 是否包含边界
- cancellationToken
- 读取的数据列表
-
-
-
- 连接到服务器
-
-
-
-
- 断开连接。
-
-
-
-
- Creates a new session.
-
- The new session object.
-
-
-
- 从服务器读取值
-
-
-
-
- 异步写opc标签
-
-
-
-
- 从服务器读取值
-
-
-
-
- 从服务器或缓存读取节点
-
-
-
-
- 读取一个节点的所有属性
-
-
-
-
- 读取节点的所有属性
-
-
-
-
- 读取一个节点的所有属性
-
- 节点信息
- 节点的特性值
-
-
-
-
-
-
- 连接处理器连接事件处理完成。
-
-
-
-
- 读取属性过程中用于描述的
-
-
-
-
- 属性的名称
-
-
-
-
- 操作结果状态描述
-
-
-
-
- 属性的类型描述
-
-
-
-
- 属性的值,如果读取错误,返回文本描述
-
-
-
-
diff --git a/framework/Foundation/ThingsGateway.Foundation.Adapter.Siemens/Siemens/DateTime.cs b/framework/Foundation/ThingsGateway.Foundation.Adapter.Siemens/Siemens/DateTime.cs
index eca649652..20f847b23 100644
--- a/framework/Foundation/ThingsGateway.Foundation.Adapter.Siemens/Siemens/DateTime.cs
+++ b/framework/Foundation/ThingsGateway.Foundation.Adapter.Siemens/Siemens/DateTime.cs
@@ -10,7 +10,6 @@
//------------------------------------------------------------------------------
#endregion
-
namespace ThingsGateway.Foundation.Adapter.Siemens;
///
diff --git a/framework/Foundation/ThingsGateway.Foundation.Adapter.Siemens/Siemens/Helper/PackHelper.cs b/framework/Foundation/ThingsGateway.Foundation.Adapter.Siemens/Siemens/Helper/PackHelper.cs
index 3c2e0a19f..c8eb1acb5 100644
--- a/framework/Foundation/ThingsGateway.Foundation.Adapter.Siemens/Siemens/Helper/PackHelper.cs
+++ b/framework/Foundation/ThingsGateway.Foundation.Adapter.Siemens/Siemens/Helper/PackHelper.cs
@@ -10,7 +10,6 @@
//------------------------------------------------------------------------------
#endregion
-
namespace ThingsGateway.Foundation.Adapter.Siemens;
internal static class PackHelper
diff --git a/framework/Foundation/ThingsGateway.Foundation.Adapter.Siemens/Siemens/SiemensS7PLC.cs b/framework/Foundation/ThingsGateway.Foundation.Adapter.Siemens/Siemens/SiemensS7PLC.cs
index f7fe75d4f..090ed8b5e 100644
--- a/framework/Foundation/ThingsGateway.Foundation.Adapter.Siemens/Siemens/SiemensS7PLC.cs
+++ b/framework/Foundation/ThingsGateway.Foundation.Adapter.Siemens/Siemens/SiemensS7PLC.cs
@@ -67,7 +67,6 @@ namespace ThingsGateway.Foundation.Adapter.Siemens
break;
}
- tcpClient.Connected += Connected;
}
///
@@ -293,8 +292,8 @@ namespace ThingsGateway.Foundation.Adapter.Siemens
///
public override void SetDataAdapter(object socketClient = null)
{
- SiemensS7PLCDataHandleAdapter DataHandleAdapter = new();
- TcpClient.SetDataHandlingAdapter(DataHandleAdapter);
+ SiemensS7PLCDataHandleAdapter dataHandleAdapter = new();
+ TcpClient.SetDataHandlingAdapter(dataHandleAdapter);
}
@@ -476,17 +475,20 @@ namespace ThingsGateway.Foundation.Adapter.Siemens
}
#endregion
- private void Connected(ITcpClient client, ConnectedEventArgs e)
+ ///
+ protected override async Task Connected(ITcpClient client, ConnectedEventArgs e)
{
try
{
- var result1 = SendThenResponse(ISO_CR);
+ NormalDataHandlingAdapter dataHandleAdapter = new();
+ TcpClient.SetDataHandlingAdapter(dataHandleAdapter);
+ var result1 = await SendThenResponseAsync(ISO_CR);
if (!result1.IsSuccess)
{
Logger?.Warning($"{client.IP} : {client.Port}:ISO_TP握手失败-{result1.Message}");
return;
}
- var result2 = SendThenResponse(S7_PN);
+ var result2 = await SendThenResponseAsync(S7_PN);
if (!result2.IsSuccess)
{
Logger?.Warning($"{client.IP} : {client.Port}:PDU初始化失败-{result2.Message}");
@@ -499,7 +501,11 @@ namespace ThingsGateway.Foundation.Adapter.Siemens
{
Logger.Exception(ex);
}
-
+ finally
+ {
+ SetDataAdapter();
+ }
+ await base.Connected(client, e);
}
}
}
\ No newline at end of file
diff --git a/framework/Foundation/ThingsGateway.Foundation.Adapter.Siemens/ThingsGateway.Foundation.Adapter.Siemens.xml b/framework/Foundation/ThingsGateway.Foundation.Adapter.Siemens/ThingsGateway.Foundation.Adapter.Siemens.xml
deleted file mode 100644
index 9c3c53e72..000000000
--- a/framework/Foundation/ThingsGateway.Foundation.Adapter.Siemens/ThingsGateway.Foundation.Adapter.Siemens.xml
+++ /dev/null
@@ -1,336 +0,0 @@
-
-
-
- ThingsGateway.Foundation.Adapter.Siemens
-
-
-
-
- 区域
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 西门子PLC地址数据信息
-
-
-
-
- bit位偏移
-
-
-
-
- 数据块代码
-
-
-
-
- DB块数据信息
-
-
-
-
- 获取起始地址
-
-
-
-
-
-
-
- 获取bit
-
-
-
-
-
-
- 解析地址
-
-
-
-
-
-
- 解析地址
-
-
-
-
-
-
-
-
-
-
-
-
-
- https://github.com/S7NetPlus/s7netplus/blob/develop/S7.Net/Types/DateTime.cs
- Contains the methods to convert between and S7 representation of datetime values.
-
-
-
-
- The maximum value supported by the specification.
-
-
-
-
- The minimum value supported by the specification.
-
-
-
-
- Parses a value from bytes.
-
- Input bytes read from PLC.
- A object representing the value read from PLC.
- Thrown when the length of
- is not 8 or any value in
- is outside the valid range of values.
-
-
-
- Parses an array of values from bytes.
-
- Input bytes read from PLC.
- An array of objects representing the values read from PLC.
- Thrown when the length of
- is not a multiple of 8 or any value in
- is outside the valid range of values.
-
-
-
- Converts a value to a byte array.
-
- The DateTime value to convert.
- A byte array containing the S7 date time representation of .
- Thrown when the value of
- is before
- or after .
-
-
-
- Converts an array of values to a byte array.
-
- The DateTime values to convert.
- A byte array containing the S7 date time representations of .
- Thrown when any value of
- is before
- or after .
-
-
-
- S7连读写请求头(包含ISO头和COTP头)
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 相关命令含义源自网络资料/Shrap7/s7netplus
-
-
-
-
- 传入PLC类型,程序内会改变相应PLC类型的S7协议LocalTSAP, RemoteTSAP等
-
-
-
-
-
-
- 当前PLC类型
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 远程TSAP,需重新连接
-
-
-
-
- 本地TSAP,需重新连接
-
-
-
-
- PDULength
-
-
-
-
- 机架号,需重新连接
-
-
-
-
- 槽号,需重新连接
-
-
-
-
-
-
-
- 读取日期
-
-
-
-
-
- 读取时间
-
-
-
-
-
- 读取变长字符串
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 写入日期
-
-
-
-
-
- 写入时间
-
-
-
-
-
- SiemensS7PLCDataHandleAdapter
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/framework/Foundation/ThingsGateway.Foundation/Foundation/BaseReadWrite/ReadWriteDevicesSerialSessionBase.cs b/framework/Foundation/ThingsGateway.Foundation/Foundation/BaseReadWrite/ReadWriteDevicesSerialSessionBase.cs
index 2465bf681..851468567 100644
--- a/framework/Foundation/ThingsGateway.Foundation/Foundation/BaseReadWrite/ReadWriteDevicesSerialSessionBase.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/Foundation/BaseReadWrite/ReadWriteDevicesSerialSessionBase.cs
@@ -24,7 +24,7 @@ public abstract class ReadWriteDevicesSerialSessionBase : ReadWriteDevicesBase
public ReadWriteDevicesSerialSessionBase(SerialSession serialSession)
{
SerialSession = serialSession;
- WaitingClientEx = SerialSession.GetWaitingClientEx(new() { BreakTrigger = true });
+ WaitingClientEx = SerialSession.GetWaitingClient(new() { ThrowBreakException = true });
SerialSession.Received -= Received;
SerialSession.Connecting -= Connecting;
SerialSession.Connected -= Connected;
@@ -40,21 +40,15 @@ public abstract class ReadWriteDevicesSerialSessionBase : ReadWriteDevicesBase
///
/// 接收解析
///
- protected virtual void Received(ByteBlock byteBlock, IRequestInfo requestInfo)
+ ///
+ ///
+ ///
+ protected virtual Task Received(SerialSession client, ReceivedDataEventArgs e)
{
+ return EasyTask.CompletedTask;
+ }
+
- }
- private void Received(SerialSession client, ByteBlock byteBlock, IRequestInfo requestInfo)
- {
- try
- {
- Received(byteBlock, requestInfo);
- }
- catch (Exception ex)
- {
- Logger.Exception(this, ex);
- }
- }
///
/// 串口管理对象
@@ -102,8 +96,8 @@ public abstract class ReadWriteDevicesSerialSessionBase : ReadWriteDevicesBase
{
try
{
- waitingOptions ??= new WaitingOptions { BreakTrigger = true, ThrowBreakException = true, AdapterFilter = AdapterFilter.NoneAll };
- ResponsedData result = SerialSession.GetWaitingClientEx(waitingOptions).SendThenResponse(data, TimeOut, cancellationToken);
+ waitingOptions ??= new WaitingOptions { ThrowBreakException = true };
+ ResponsedData result = SerialSession.GetWaitingClient(waitingOptions).SendThenResponse(data, TimeOut, cancellationToken);
return OperResult.CreateSuccessResult(result.Data);
}
catch (Exception ex)
@@ -117,8 +111,8 @@ public abstract class ReadWriteDevicesSerialSessionBase : ReadWriteDevicesBase
{
try
{
- waitingOptions ??= new WaitingOptions { ThrowBreakException = true, AdapterFilter = AdapterFilter.NoneAll };
- ResponsedData result = await SerialSession.GetWaitingClientEx(waitingOptions).SendThenResponseAsync(data, TimeOut, cancellationToken);
+ waitingOptions ??= new WaitingOptions { ThrowBreakException = true };
+ ResponsedData result = await SerialSession.GetWaitingClient(waitingOptions).SendThenResponseAsync(data, TimeOut, cancellationToken);
return OperResult.CreateSuccessResult(result.Data);
}
catch (Exception ex)
@@ -132,24 +126,34 @@ public abstract class ReadWriteDevicesSerialSessionBase : ReadWriteDevicesBase
{
return SerialSession.SerialProperty.ToString();
}
- private void Connected(ISerialSession client, ConnectedEventArgs e)
+ ///
+ /// Connected
+ ///
+ ///
+ ///
+ ///
+ protected virtual Task Connected(ISerialSession client, ConnectedEventArgs e)
{
Logger?.Debug(client.SerialProperty.ToString() + "连接成功");
+ SetDataAdapter();
+ return EasyTask.CompletedTask;
}
- private void Connecting(ISerialSession client, SerialConnectingEventArgs e)
+ private Task Connecting(ISerialSession client, SerialConnectingEventArgs e)
{
Logger?.Debug(client.SerialProperty.ToString() + "正在连接");
- SetDataAdapter();
+ return EasyTask.CompletedTask;
}
- private void Disconnected(ISerialSessionBase client, DisconnectEventArgs e)
+ private Task Disconnected(ISerialSessionBase client, DisconnectEventArgs e)
{
Logger?.Debug(client.SerialProperty.ToString() + "断开连接-" + e.Message);
+ return EasyTask.CompletedTask;
}
- private void Disconnecting(ISerialSessionBase client, DisconnectEventArgs e)
+ private Task Disconnecting(ISerialSessionBase client, DisconnectEventArgs e)
{
Logger?.Debug(client.SerialProperty.ToString() + "正在主动断开连接-" + e.Message);
+ return EasyTask.CompletedTask;
}
}
\ No newline at end of file
diff --git a/framework/Foundation/ThingsGateway.Foundation/Foundation/BaseReadWrite/ReadWriteDevicesTcpClientBase.cs b/framework/Foundation/ThingsGateway.Foundation/Foundation/BaseReadWrite/ReadWriteDevicesTcpClientBase.cs
index b318277ae..b91a8f44e 100644
--- a/framework/Foundation/ThingsGateway.Foundation/Foundation/BaseReadWrite/ReadWriteDevicesTcpClientBase.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/Foundation/BaseReadWrite/ReadWriteDevicesTcpClientBase.cs
@@ -23,7 +23,7 @@ public abstract class ReadWriteDevicesTcpClientBase : ReadWriteDevicesBase
public ReadWriteDevicesTcpClientBase(TcpClient tcpClient)
{
TcpClient = tcpClient;
- WaitingClientEx = TcpClient.GetWaitingClientEx(new() { BreakTrigger = true });
+ WaitingClientEx = TcpClient.GetWaitingClient(new() { ThrowBreakException = true });
TcpClient.Connecting -= Connecting;
TcpClient.Connected -= Connected;
TcpClient.Disconnecting -= Disconnecting;
@@ -59,7 +59,7 @@ public abstract class ReadWriteDevicesTcpClientBase : ReadWriteDevicesBase
///
public override Task ConnectAsync(CancellationToken cancellationToken)
{
- return TcpClient.ConnectAsync(ConnectTimeOut);
+ return TcpClient.ConnectAsync(ConnectTimeOut, cancellationToken);
}
///
@@ -86,8 +86,8 @@ public abstract class ReadWriteDevicesTcpClientBase : ReadWriteDevicesBase
{
try
{
- waitingOptions ??= new WaitingOptions { BreakTrigger = true, ThrowBreakException = true, AdapterFilter = AdapterFilter.NoneAll };
- ResponsedData result = TcpClient.GetWaitingClientEx(waitingOptions).SendThenResponse(data, TimeOut, cancellationToken);
+ waitingOptions ??= new WaitingOptions { ThrowBreakException = true, };
+ ResponsedData result = TcpClient.GetWaitingClient(waitingOptions).SendThenResponse(data, TimeOut, cancellationToken);
return OperResult.CreateSuccessResult(result.Data);
}
catch (Exception ex)
@@ -101,8 +101,8 @@ public abstract class ReadWriteDevicesTcpClientBase : ReadWriteDevicesBase
{
try
{
- waitingOptions ??= new WaitingOptions { ThrowBreakException = true, AdapterFilter = AdapterFilter.NoneAll };
- ResponsedData result = await TcpClient.GetWaitingClientEx(waitingOptions).SendThenResponseAsync(data, TimeOut, cancellationToken);
+ waitingOptions ??= new WaitingOptions { ThrowBreakException = true };
+ ResponsedData result = await TcpClient.GetWaitingClient(waitingOptions).SendThenResponseAsync(data, TimeOut, cancellationToken);
return OperResult.CreateSuccessResult(result.Data);
}
catch (Exception ex)
@@ -116,24 +116,34 @@ public abstract class ReadWriteDevicesTcpClientBase : ReadWriteDevicesBase
{
return TcpClient.RemoteIPHost.ToString();
}
- private void Connected(ITcpClient client, ConnectedEventArgs e)
+ ///
+ /// Connected
+ ///
+ ///
+ ///
+ ///
+ protected virtual Task Connected(ITcpClient client, ConnectedEventArgs e)
{
Logger?.Debug(client.RemoteIPHost.ToString() + "连接成功");
+ SetDataAdapter();
+ return EasyTask.CompletedTask;
}
- private void Connecting(ITcpClient client, ConnectingEventArgs e)
+ private Task Connecting(ITcpClient client, ConnectingEventArgs e)
{
Logger?.Debug(client.RemoteIPHost.ToString() + "正在连接");
- SetDataAdapter();
+ return EasyTask.CompletedTask;
}
- private void Disconnected(ITcpClientBase client, DisconnectEventArgs e)
+ private Task Disconnected(ITcpClientBase client, DisconnectEventArgs e)
{
Logger?.Debug(client.IP + ":" + client.Port + "断开连接-" + e.Message);
+ return EasyTask.CompletedTask;
}
- private void Disconnecting(ITcpClientBase client, DisconnectEventArgs e)
+ private Task Disconnecting(ITcpClientBase client, DisconnectEventArgs e)
{
Logger?.Debug(client.IP + ":" + client.Port + "正在主动断开连接-" + e.Message);
+ return EasyTask.CompletedTask;
}
}
\ No newline at end of file
diff --git a/framework/Foundation/ThingsGateway.Foundation/Foundation/BaseReadWrite/ReadWriteDevicesTcpServerBase.cs b/framework/Foundation/ThingsGateway.Foundation/Foundation/BaseReadWrite/ReadWriteDevicesTcpServerBase.cs
index cbb282acf..0c556764f 100644
--- a/framework/Foundation/ThingsGateway.Foundation/Foundation/BaseReadWrite/ReadWriteDevicesTcpServerBase.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/Foundation/BaseReadWrite/ReadWriteDevicesTcpServerBase.cs
@@ -77,57 +77,54 @@ public abstract class ReadWriteDevicesTcpServerBase : ReadWriteDevicesBase
if (CascadeDisposal)
TcpService.SafeDispose();
}
+ ///
+ /// 接收解析
+ ///
+ ///
+ ///
+ ///
+ protected virtual Task Received(SocketClient client, ReceivedDataEventArgs e)
+ {
+ return EasyTask.CompletedTask;
+ }
///
public override string ToString()
{
return TcpService.ServerName;
}
- ///
- /// 接收解析
- ///
- protected virtual void Received(SocketClient client, IRequestInfo requestInfo)
- {
- }
///
///
///
///
///
- protected virtual void Connected(SocketClient client, ConnectedEventArgs e)
+ protected virtual Task Connected(SocketClient client, ConnectedEventArgs e)
{
Logger?.Debug(client.IP + ":" + client.Port + "连接成功");
+ return EasyTask.CompletedTask;
}
///
- protected virtual void Connecting(SocketClient client, ConnectingEventArgs e)
+ protected virtual Task Connecting(SocketClient client, ConnectingEventArgs e)
{
Logger?.Debug(client.IP + ":" + client.Port + "正在连接");
SetDataAdapter(client);
+ return EasyTask.CompletedTask;
}
///
- protected virtual void Disconnected(ITcpClientBase client, DisconnectEventArgs e)
+ protected virtual Task Disconnected(ITcpClientBase client, DisconnectEventArgs e)
{
Logger?.Debug(client.IP + ":" + client.Port + "断开连接-" + e.Message);
+ return EasyTask.CompletedTask;
}
///
- protected virtual void Disconnecting(ITcpClientBase client, DisconnectEventArgs e)
+ protected virtual Task Disconnecting(ITcpClientBase client, DisconnectEventArgs e)
{
Logger?.Debug(client.IP + ":" + client.Port + "正在主动断开连接-" + e.Message);
+ return EasyTask.CompletedTask;
}
- private void Received(SocketClient client, ByteBlock byteBlock, IRequestInfo requestInfo)
- {
- try
- {
- Received(client, requestInfo);
- }
- catch (Exception ex)
- {
- Logger.Exception(this, ex);
- }
- }
}
\ No newline at end of file
diff --git a/framework/Foundation/ThingsGateway.Foundation/Foundation/BaseReadWrite/ReadWriteDevicesUdpSessionBase.cs b/framework/Foundation/ThingsGateway.Foundation/Foundation/BaseReadWrite/ReadWriteDevicesUdpSessionBase.cs
index b10cba786..b51d372a7 100644
--- a/framework/Foundation/ThingsGateway.Foundation/Foundation/BaseReadWrite/ReadWriteDevicesUdpSessionBase.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/Foundation/BaseReadWrite/ReadWriteDevicesUdpSessionBase.cs
@@ -22,7 +22,7 @@ public abstract class ReadWriteDevicesUdpSessionBase : ReadWriteDevicesBase
{
UdpSession = udpSession;
SetDataAdapter();
- WaitingClientEx = UdpSession.GetWaitingClientEx(new() { BreakTrigger = true });
+ WaitingClientEx = UdpSession.GetWaitingClient(new() { ThrowBreakException = true });
}
///
@@ -64,8 +64,8 @@ public abstract class ReadWriteDevicesUdpSessionBase : ReadWriteDevicesBase
{
try
{
- waitingOptions ??= new WaitingOptions { ThrowBreakException = true, AdapterFilter = AdapterFilter.NoneAll };
- ResponsedData result = UdpSession.GetWaitingClientEx(waitingOptions).SendThenResponse(data, TimeOut, cancellationToken);
+ waitingOptions ??= new WaitingOptions { ThrowBreakException = true };
+ ResponsedData result = UdpSession.GetWaitingClient(waitingOptions).SendThenResponse(data, TimeOut, cancellationToken);
return OperResult.CreateSuccessResult(result.Data);
}
catch (Exception ex)
@@ -79,8 +79,8 @@ public abstract class ReadWriteDevicesUdpSessionBase : ReadWriteDevicesBase
{
try
{
- waitingOptions ??= new WaitingOptions { ThrowBreakException = true, AdapterFilter = AdapterFilter.NoneAll };
- ResponsedData result = await UdpSession.GetWaitingClientEx(waitingOptions).SendThenResponseAsync(data, TimeOut, cancellationToken);
+ waitingOptions ??= new WaitingOptions { ThrowBreakException = true };
+ ResponsedData result = await UdpSession.GetWaitingClient(waitingOptions).SendThenResponseAsync(data, TimeOut, cancellationToken);
return OperResult.CreateSuccessResult(result.Data);
}
catch (Exception ex)
diff --git a/framework/Foundation/ThingsGateway.Foundation/Foundation/DataHandleAdapter/ReadWriteDevicesTcpDataHandleAdapter.cs b/framework/Foundation/ThingsGateway.Foundation/Foundation/DataHandleAdapter/ReadWriteDevicesTcpDataHandleAdapter.cs
index 77fed8c95..0d170183f 100644
--- a/framework/Foundation/ThingsGateway.Foundation/Foundation/DataHandleAdapter/ReadWriteDevicesTcpDataHandleAdapter.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/Foundation/DataHandleAdapter/ReadWriteDevicesTcpDataHandleAdapter.cs
@@ -143,6 +143,21 @@ public abstract class ReadWriteDevicesTcpDataHandleAdapter : CustomDat
GoSend(bytes, 0, bytes.Length);
Logger?.Trace($"{FoundationConst.LogMessageHeader}{ToString()}- 发送:{Request.SendBytes.ToHexString(' ')}");
}
+ ///
+ /// 发送方法,会重新建立
+ ///
+ protected async Task GoSendAsync(byte[] item)
+ {
+ byte[] bytes;
+ if (IsSendPackCommand)
+ bytes = PackCommand(item);
+ else
+ bytes = item;
+ Request = GetInstance();
+ Request.SendBytes = bytes;
+ await GoSendAsync(bytes, 0, bytes.Length);
+ Logger?.Trace($"{FoundationConst.LogMessageHeader}{ToString()}- 发送:{Request.SendBytes.ToHexString(' ')}");
+ }
///
protected override void PreviewSend(byte[] buffer, int offset, int length)
@@ -150,6 +165,12 @@ public abstract class ReadWriteDevicesTcpDataHandleAdapter : CustomDat
GoSend(buffer);
}
+ ///
+ protected override Task PreviewSendAsync(byte[] buffer, int offset, int length)
+ {
+ return GoSendAsync(buffer);
+ }
+
///
/// 报文拆包
///
diff --git a/framework/Foundation/ThingsGateway.Foundation/Foundation/DataHandleAdapter/ReadWriteDevicesUdpDataHandleAdapter.cs b/framework/Foundation/ThingsGateway.Foundation/Foundation/DataHandleAdapter/ReadWriteDevicesUdpDataHandleAdapter.cs
index 78783d61b..0d9449275 100644
--- a/framework/Foundation/ThingsGateway.Foundation/Foundation/DataHandleAdapter/ReadWriteDevicesUdpDataHandleAdapter.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/Foundation/DataHandleAdapter/ReadWriteDevicesUdpDataHandleAdapter.cs
@@ -128,11 +128,6 @@ public abstract class ReadWriteDevicesUdpDataHandleAdapter : UdpDataHa
{
throw new System.NotImplementedException();//因为设置了不支持拼接发送,所以该方法可以不实现。
}
- ///
- protected override void PreviewSend(IRequestInfo requestInfo)
- {
- throw new System.NotImplementedException();//因为设置了不支持,所以该方法可以不实现。
- }
///
protected override void Reset()
diff --git a/framework/Foundation/ThingsGateway.Foundation/ThingsGateway.Foundation.csproj b/framework/Foundation/ThingsGateway.Foundation/ThingsGateway.Foundation.csproj
index f29b9f7bf..78cf7d45d 100644
--- a/framework/Foundation/ThingsGateway.Foundation/ThingsGateway.Foundation.csproj
+++ b/framework/Foundation/ThingsGateway.Foundation/ThingsGateway.Foundation.csproj
@@ -19,5 +19,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/Common/DisposableObject.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/Common/DisposableObject.cs
index 6cd075fe5..b51f652d0 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/Common/DisposableObject.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/Common/DisposableObject.cs
@@ -30,7 +30,7 @@ namespace ThingsGateway.Foundation.Core
/// 具有释放的对象。
/// 并未实现析构函数相关。
///
- public class DisposableObject : IDisposable
+ public partial class DisposableObject : IDisposable
{
///
/// 判断是否已释放。
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/DataAdapter/DataHandlingAdapter.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/DataAdapter/DataHandlingAdapter.cs
index cf39ca15b..fad43c73a 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/DataAdapter/DataHandlingAdapter.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/DataAdapter/DataHandlingAdapter.cs
@@ -69,14 +69,6 @@ namespace ThingsGateway.Foundation.Core
this.Owner = owner;
}
- ///
- /// 发送数据的切入点,该方法由框架自动调用。
- ///
- ///
- public void SendInput(IRequestInfo requestInfo)
- {
- this.PreviewSend(requestInfo);
- }
///
/// 在解析时发生错误。
@@ -96,11 +88,6 @@ namespace ThingsGateway.Foundation.Core
}
}
- ///
- /// 当发送数据前预先处理数据
- ///
- ///
- protected abstract void PreviewSend(IRequestInfo requestInfo);
///
/// 重置解析器到初始状态,一般在被触发时,由返回值指示是否调用。
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/DataAdapter/NormalDataHandlingAdapter.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/DataAdapter/NormalDataHandlingAdapter.cs
index e66b81f17..b6e092a35 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/DataAdapter/NormalDataHandlingAdapter.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/DataAdapter/NormalDataHandlingAdapter.cs
@@ -78,6 +78,24 @@ namespace ThingsGateway.Foundation.Core
throw new System.NotImplementedException();
}
+ ///
+ protected override Task PreviewSendAsync(IRequestInfo requestInfo)
+ {
+ throw new NotImplementedException();
+ }
+
+ ///
+ protected override Task PreviewSendAsync(byte[] buffer, int offset, int length)
+ {
+ return this.GoSendAsync(buffer, offset, length);
+ }
+
+ ///
+ protected override Task PreviewSendAsync(IList> transferBytes)
+ {
+ throw new NotImplementedException();
+ }
+
///
///
///
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/DataAdapter/Package/FixedHeaderPackageAdapter.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/DataAdapter/Package/FixedHeaderPackageAdapter.cs
index b1e39dbb5..b54bcb721 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/DataAdapter/Package/FixedHeaderPackageAdapter.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/DataAdapter/Package/FixedHeaderPackageAdapter.cs
@@ -242,6 +242,131 @@ namespace ThingsGateway.Foundation.Core
throw new NotImplementedException();
}
+ ///
+ protected override Task PreviewSendAsync(IRequestInfo requestInfo)
+ {
+ throw new NotImplementedException();
+ }
+
+ ///
+ protected override async Task PreviewSendAsync(byte[] buffer, int offset, int length)
+ {
+ if (length < this.MinPackageSize)
+ {
+ throw new Exception("发送数据小于设定值,相同解析器可能无法收到有效数据,已终止发送");
+ }
+
+ if (length > this.MaxPackageSize)
+ {
+ throw new Exception("发送数据大于设定值,相同解析器可能无法收到有效数据,已终止发送");
+ }
+
+ ByteBlock byteBlock = null;
+ byte[] lenBytes = null;
+
+ switch (this.FixedHeaderType)
+ {
+ case FixedHeaderType.Byte:
+ {
+ var dataLen = (byte)(length - offset);
+ byteBlock = new ByteBlock(dataLen + 1);
+ lenBytes = new byte[] { dataLen };
+ break;
+ }
+ case FixedHeaderType.Ushort:
+ {
+ var dataLen = (ushort)(length - offset);
+ byteBlock = new ByteBlock(dataLen + 2);
+ lenBytes = TouchSocketBitConverter.Default.GetBytes(dataLen);
+ break;
+ }
+ case FixedHeaderType.Int:
+ {
+ var dataLen = length - offset;
+ byteBlock = new ByteBlock(dataLen + 4);
+ lenBytes = TouchSocketBitConverter.Default.GetBytes(dataLen);
+ break;
+ }
+ }
+
+ try
+ {
+ byteBlock.Write(lenBytes);
+ byteBlock.Write(buffer, offset, length);
+ await this.GoSendAsync(byteBlock.Buffer, 0, byteBlock.Len);
+ }
+ finally
+ {
+ byteBlock.Dispose();
+ }
+ }
+
+ ///
+ protected override async Task PreviewSendAsync(IList> transferBytes)
+ {
+ if (transferBytes.Count == 0)
+ {
+ return;
+ }
+
+ var length = 0;
+ foreach (var item in transferBytes)
+ {
+ length += item.Count;
+ }
+
+ if (length < this.MinPackageSize)
+ {
+ throw new Exception("发送数据小于设定值,相同解析器可能无法收到有效数据,已终止发送");
+ }
+
+ if (length > this.MaxPackageSize)
+ {
+ throw new Exception("发送数据大于设定值,相同解析器可能无法收到有效数据,已终止发送");
+ }
+
+ ByteBlock byteBlock = null;
+ byte[] lenBytes = null;
+
+ switch (this.FixedHeaderType)
+ {
+ case FixedHeaderType.Byte:
+ {
+ var dataLen = (byte)length;
+ byteBlock = new ByteBlock(dataLen + 1);
+ lenBytes = new byte[] { dataLen };
+ break;
+ }
+ case FixedHeaderType.Ushort:
+ {
+ var dataLen = (ushort)length;
+ byteBlock = new ByteBlock(dataLen + 2);
+ lenBytes = TouchSocketBitConverter.Default.GetBytes(dataLen);
+ break;
+ }
+ case FixedHeaderType.Int:
+ {
+ byteBlock = new ByteBlock(length + 4);
+ lenBytes = TouchSocketBitConverter.Default.GetBytes(length);
+ break;
+ }
+ }
+
+ try
+ {
+ byteBlock.Write(lenBytes);
+ foreach (var item in transferBytes)
+ {
+ byteBlock.Write(item.Array, item.Offset, item.Count);
+ }
+ await this.GoSendAsync(byteBlock.Buffer, 0, byteBlock.Len);
+ }
+ finally
+ {
+ byteBlock.Dispose();
+ }
+ }
+
///
///
///
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/DataAdapter/Package/FixedSizePackageAdapter.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/DataAdapter/Package/FixedSizePackageAdapter.cs
index 6dc97ddeb..290d4ade1 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/DataAdapter/Package/FixedSizePackageAdapter.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/DataAdapter/Package/FixedSizePackageAdapter.cs
@@ -183,6 +183,70 @@ namespace ThingsGateway.Foundation.Core
throw new NotImplementedException();
}
+ ///
+ protected override Task PreviewSendAsync(IRequestInfo requestInfo)
+ {
+ throw new NotImplementedException();
+ }
+
+ ///
+ protected override async Task PreviewSendAsync(byte[] buffer, int offset, int length)
+ {
+ var dataLen = length - offset;
+ if (dataLen > this.FixedSize)
+ {
+ throw new OverlengthException("发送的数据包长度大于FixedSize");
+ }
+ var byteBlock = new ByteBlock(this.FixedSize);
+
+ byteBlock.Write(buffer, offset, length);
+ for (var i = byteBlock.Pos; i < this.FixedSize; i++)
+ {
+ byteBlock.Buffer[i] = 0;
+ }
+ byteBlock.SetLength(this.FixedSize);
+ try
+ {
+ await this.GoSendAsync(byteBlock.Buffer, 0, byteBlock.Len);
+ }
+ finally
+ {
+ byteBlock.Dispose();
+ }
+ }
+
+ ///
+ protected override async Task PreviewSendAsync(IList> transferBytes)
+ {
+ var length = 0;
+ foreach (var item in transferBytes)
+ {
+ length += item.Count;
+ }
+
+ if (length > this.FixedSize)
+ {
+ throw new OverlengthException("发送的数据包长度大于FixedSize");
+ }
+ var byteBlock = new ByteBlock(this.FixedSize);
+
+ foreach (var item in transferBytes)
+ {
+ byteBlock.Write(item.Array, item.Offset, item.Count);
+ }
+
+ Array.Clear(byteBlock.Buffer, byteBlock.Pos, this.FixedSize);
+ byteBlock.SetLength(this.FixedSize);
+ try
+ {
+ await this.GoSendAsync(byteBlock.Buffer, 0, byteBlock.Len);
+ }
+ finally
+ {
+ byteBlock.Dispose();
+ }
+ }
+
///
///
///
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/DataAdapter/Package/TerminatorPackageAdapter.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/DataAdapter/Package/TerminatorPackageAdapter.cs
index f44b188a2..76b95c5e5 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/DataAdapter/Package/TerminatorPackageAdapter.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/DataAdapter/Package/TerminatorPackageAdapter.cs
@@ -240,5 +240,64 @@ namespace ThingsGateway.Foundation.Core
byteBlock.Dispose();
}
}
+
+ ///
+ protected override Task PreviewSendAsync(IRequestInfo requestInfo)
+ {
+ throw new NotImplementedException();
+ }
+
+ ///
+ protected override async Task PreviewSendAsync(byte[] buffer, int offset, int length)
+ {
+ if (length > this.MaxPackageSize)
+ {
+ throw new Exception("发送的数据长度大于适配器设定的最大值,接收方可能会抛弃。");
+ }
+ var dataLen = length - offset + this.m_terminatorCode.Length;
+ var byteBlock = new ByteBlock(dataLen);
+ byteBlock.Write(buffer, offset, length);
+ byteBlock.Write(this.m_terminatorCode);
+
+ try
+ {
+ await this.GoSendAsync(byteBlock.Buffer, 0, byteBlock.Len);
+ }
+ finally
+ {
+ byteBlock.Dispose();
+ }
+ }
+
+ ///
+ protected override async Task PreviewSendAsync(IList> transferBytes)
+ {
+ var length = 0;
+ foreach (var item in transferBytes)
+ {
+ length += item.Count;
+ }
+ if (length > this.MaxPackageSize)
+ {
+ throw new Exception("发送的数据长度大于适配器设定的最大值,接收方可能会抛弃。");
+ }
+ var dataLen = length + this.m_terminatorCode.Length;
+ var byteBlock = new ByteBlock(dataLen);
+ foreach (var item in transferBytes)
+ {
+ byteBlock.Write(item.Array, item.Offset, item.Count);
+ }
+
+ byteBlock.Write(this.m_terminatorCode);
+
+ try
+ {
+ await this.GoSendAsync(byteBlock.Buffer, 0, byteBlock.Len);
+ }
+ finally
+ {
+ byteBlock.Dispose();
+ }
+ }
}
}
\ No newline at end of file
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/DataAdapter/SingleStreamAdapterOption.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/DataAdapter/SingleStreamAdapterOption.cs
index ef58c32b1..0efd7ee87 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/DataAdapter/SingleStreamAdapterOption.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/DataAdapter/SingleStreamAdapterOption.cs
@@ -10,6 +10,19 @@
//------------------------------------------------------------------------------
#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
{
///
@@ -37,4 +50,4 @@ namespace ThingsGateway.Foundation.Core
///
public bool? UpdateCacheTimeWhenRev { get; set; }
}
-}
+}
\ No newline at end of file
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/DataAdapter/SingleStreamDataHandlingAdapter.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/DataAdapter/SingleStreamDataHandlingAdapter.cs
index 405ea2591..d296be02b 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/DataAdapter/SingleStreamDataHandlingAdapter.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/DataAdapter/SingleStreamDataHandlingAdapter.cs
@@ -36,9 +36,9 @@ namespace ThingsGateway.Foundation.Core
public TimeSpan CacheTimeout { get; set; } = TimeSpan.FromSeconds(1);
///
- /// 是否启用缓存超时。默认true。
+ /// 是否启用缓存超时。默认false。
///
- public bool CacheTimeoutEnable { get; set; } = true;
+ public bool CacheTimeoutEnable { get; set; } = false;
///
/// 当接收数据处理完成后,回调该函数执行接收
@@ -46,10 +46,15 @@ namespace ThingsGateway.Foundation.Core
public Action ReceivedCallBack { get; set; }
///
- /// 当接收数据处理完成后,回调该函数执行发送
+ /// 当发送数据处理完成后,回调该函数执行发送
///
public Action SendCallBack { get; set; }
+ ///
+ /// 当发送数据处理完成后,回调该函数执行异步发送
+ ///
+ public Func SendAsyncCallBack { get; set; }
+
///
/// 是否在收到数据时,即刷新缓存时间。默认true。
///
@@ -64,6 +69,12 @@ namespace ThingsGateway.Foundation.Core
///
protected DateTime LastCacheTime { get; set; }
+ ///
+ public override bool CanSendRequestInfo => false;
+
+ ///
+ public override bool CanSplicingSend => false;
+
///
/// 收到数据的切入点,该方法由框架自动调用。
///
@@ -80,6 +91,17 @@ namespace ThingsGateway.Foundation.Core
}
}
+ #region SendInput
+
+ ///
+ /// 发送数据的切入点,该方法由框架自动调用。
+ ///
+ ///
+ public void SendInput(IRequestInfo requestInfo)
+ {
+ this.PreviewSend(requestInfo);
+ }
+
///
/// 发送数据的切入点,该方法由框架自动调用。
///
@@ -100,6 +122,98 @@ namespace ThingsGateway.Foundation.Core
this.PreviewSend(transferBytes);
}
+ ///
+ /// 发送数据的切入点,该方法由框架自动调用。
+ ///
+ ///
+ ///
+ public Task SendInputAsync(IRequestInfo requestInfo)
+ {
+ return this.PreviewSendAsync(requestInfo);
+ }
+
+ ///
+ /// 发送数据的切入点,该方法由框架自动调用。
+ ///
+ ///
+ ///
+ ///
+ public Task SendInputAsync(byte[] buffer, int offset, int length)
+ {
+ return this.PreviewSendAsync(buffer, offset, length);
+ }
+
+ ///
+ /// 发送数据的切入点,该方法由框架自动调用。
+ ///
+ ///
+ public Task SendInputAsync(IList> transferBytes)
+ {
+ return this.PreviewSendAsync(transferBytes);
+ }
+
+ ///
+ /// 当发送数据前预先处理数据
+ ///
+ ///
+ protected virtual void PreviewSend(IRequestInfo requestInfo)
+ {
+ throw new NotImplementedException();
+ }
+
+ ///
+ /// 当发送数据前预先处理数据
+ ///
+ /// 数据
+ /// 偏移
+ /// 长度
+ protected virtual void PreviewSend(byte[] buffer, int offset, int length)
+ {
+ this.GoSend(buffer, offset, length);
+ }
+
+ ///
+ /// 组合发送预处理数据,
+ /// 当属性SplicingSend实现为True时,系统才会调用该方法。
+ ///
+ /// 代发送数据组合
+ protected virtual void PreviewSend(IList> transferBytes)
+ {
+ throw new NotImplementedException();
+ }
+
+ ///
+ /// 当发送数据前预先处理数据
+ ///
+ ///
+ protected virtual Task PreviewSendAsync(IRequestInfo requestInfo)
+ {
+ throw new NotImplementedException();
+ }
+
+ ///
+ /// 当发送数据前预先处理数据
+ ///
+ /// 数据
+ /// 偏移
+ /// 长度
+ protected virtual Task PreviewSendAsync(byte[] buffer, int offset, int length)
+ {
+ return this.GoSendAsync(buffer, offset, length);
+ }
+
+ ///
+ /// 组合发送预处理数据,
+ /// 当属性SplicingSend实现为True时,系统才会调用该方法。
+ ///
+ /// 代发送数据组合
+ protected virtual Task PreviewSendAsync(IList> transferBytes)
+ {
+ throw new NotImplementedException();
+ }
+
+ #endregion SendInput
+
///
///
///
@@ -130,27 +244,24 @@ namespace ThingsGateway.Foundation.Core
this.SendCallBack.Invoke(buffer, offset, length);
}
+ ///
+ /// 异步发送已经经过预先处理后的数据
+ ///
+ ///
+ ///
+ ///
+ ///
+ protected Task GoSendAsync(byte[] buffer, int offset, int length)
+ {
+ return this.SendAsyncCallBack.Invoke(buffer, offset, length);
+ }
+
///
/// 当接收到数据后预先处理数据,然后调用处理数据
///
///
protected abstract void PreviewReceived(ByteBlock byteBlock);
- ///
- /// 当发送数据前预先处理数据
- ///
- /// 数据
- /// 偏移
- /// 长度
- protected abstract void PreviewSend(byte[] buffer, int offset, int length);
-
- ///
- /// 组合发送预处理数据,
- /// 当属性SplicingSend实现为True时,系统才会调用该方法。
- ///
- /// 代发送数据组合
- protected abstract void PreviewSend(IList> transferBytes);
-
///
/// 重置解析器到初始状态,一般在被触发时,由返回值指示是否调用。
///
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/DataAdapter/Test/SingleStreamDataAdapterTester.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/DataAdapter/Test/SingleStreamDataAdapterTester.cs
index 4596419f0..aa9e183f8 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/DataAdapter/Test/SingleStreamDataAdapterTester.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/DataAdapter/Test/SingleStreamDataAdapterTester.cs
@@ -63,9 +63,11 @@ namespace ThingsGateway.Foundation.Core
///
public static SingleStreamDataAdapterTester CreateTester(SingleStreamDataHandlingAdapter adapter, int bufferLength = 1024, Action receivedCallBack = default)
{
- var tester = new SingleStreamDataAdapterTester();
- tester.m_adapter = adapter;
- tester.m_bufferLength = bufferLength;
+ var tester = new SingleStreamDataAdapterTester
+ {
+ m_adapter = adapter,
+ m_bufferLength = bufferLength
+ };
adapter.SendCallBack = tester.SendCallback;
adapter.ReceivedCallBack = tester.OnReceived;
tester.m_receivedCallBack = receivedCallBack;
@@ -129,7 +131,7 @@ namespace ThingsGateway.Foundation.Core
{
while (!this.m_dispose)
{
- if (this.tryGet(out var byteBlocks))
+ if (this.TryGet(out var byteBlocks))
{
foreach (var block in byteBlocks)
{
@@ -163,7 +165,7 @@ namespace ThingsGateway.Foundation.Core
this.m_asyncBytes.Enqueue(asyncByte);
}
- private bool tryGet(out List byteBlocks)
+ private bool TryGet(out List byteBlocks)
{
byteBlocks = new List();
ByteBlock block = null;
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/Dependency/Container.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/Dependency/Container.cs
index f864e8a0a..f6def309e 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/Dependency/Container.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/Dependency/Container.cs
@@ -70,10 +70,9 @@ namespace ThingsGateway.Foundation.Core
///
///
///
- ///
///
///
- public object Resolve(Type fromType, object[] ps = null, string key = "")
+ public object Resolve(Type fromType, string key = "")
{
if (fromType == typeof(IContainer))
{
@@ -108,11 +107,11 @@ namespace ThingsGateway.Foundation.Core
{
if (descriptor.ToType.IsGenericType)
{
- return (descriptor.ToInstance = this.Create(descriptor, descriptor.ToType.MakeGenericType(fromType.GetGenericArguments()), ps));
+ return (descriptor.ToInstance = this.Create(descriptor, descriptor.ToType.MakeGenericType(fromType.GetGenericArguments())));
}
else
{
- return (descriptor.ToInstance = this.Create(descriptor, descriptor.ToType, ps));
+ return descriptor.ToInstance = this.Create(descriptor, descriptor.ToType);
}
}
}
@@ -120,11 +119,11 @@ namespace ThingsGateway.Foundation.Core
if (descriptor.ToType.IsGenericType)
{
- return this.Create(descriptor, descriptor.ToType.MakeGenericType(fromType.GetGenericArguments()), ps);
+ return this.Create(descriptor, descriptor.ToType.MakeGenericType(fromType.GetGenericArguments()));
}
else
{
- return this.Create(descriptor, descriptor.ToType, ps);
+ return this.Create(descriptor, descriptor.ToType);
}
}
}
@@ -143,10 +142,10 @@ namespace ThingsGateway.Foundation.Core
}
lock (descriptor)
{
- return descriptor.ToInstance ??= this.Create(descriptor, descriptor.ToType, ps);
+ return descriptor.ToInstance ??= this.Create(descriptor, descriptor.ToType);
}
}
- return this.Create(descriptor, descriptor.ToType, ps);
+ return this.Create(descriptor, descriptor.ToType);
}
else
{
@@ -172,7 +171,7 @@ namespace ThingsGateway.Foundation.Core
this.m_registrations.TryRemove(k, out _);
}
- private object Create(DependencyDescriptor descriptor, Type toType, object[] ops)
+ private object Create(DependencyDescriptor descriptor, Type toType)
{
var ctor = toType.GetConstructors().FirstOrDefault(x => x.IsDefined(typeof(DependencyInjectAttribute), true));
if (ctor is null)
@@ -198,28 +197,21 @@ namespace ThingsGateway.Foundation.Core
{
for (var i = 0; i < parameters.Length; i++)
{
- if (ops != null && ops.Length - 1 >= i)
+ if (parameters[i].ParameterType.IsPrimitive || parameters[i].ParameterType == typeof(string))
{
- ps[i] = ops[i];
+ ps[i] = parameters[i].HasDefaultValue ? parameters[i].DefaultValue : default;
}
else
{
- if (parameters[i].ParameterType.IsPrimitive || parameters[i].ParameterType == typeof(string))
+ if (parameters[i].IsDefined(typeof(DependencyInjectAttribute), true))
{
- ps[i] = parameters[i].HasDefaultValue ? parameters[i].DefaultValue : default;
+ var attribute = parameters[i].GetCustomAttribute();
+ var type = attribute.Type ?? parameters[i].ParameterType;
+ ps[i] = this.Resolve(type, attribute.Key);
}
else
{
- if (parameters[i].IsDefined(typeof(DependencyInjectAttribute), true))
- {
- var attribute = parameters[i].GetCustomAttribute();
- var type = attribute.Type ?? parameters[i].ParameterType;
- ps[i] = this.Resolve(type, default, attribute.Key);
- }
- else
- {
- ps[i] = this.Resolve(parameters[i].ParameterType, null);
- }
+ ps[i] = this.Resolve(parameters[i].ParameterType, null);
}
}
}
@@ -239,7 +231,7 @@ namespace ThingsGateway.Foundation.Core
{
var attribute = item.GetCustomAttribute();
var type = attribute.Type ?? item.PropertyType;
- obj = this.Resolve(type, default, attribute.Key);
+ obj = this.Resolve(type, attribute.Key);
}
else
{
@@ -259,28 +251,21 @@ namespace ThingsGateway.Foundation.Core
ps = new object[parameters.Length];
for (var i = 0; i < ps.Length; i++)
{
- if (ops != null && ops.Length - 1 >= i)
+ if (parameters[i].ParameterType.IsPrimitive || parameters[i].ParameterType == typeof(string))
{
- ps[i] = ops[i];
+ ps[i] = parameters[i].HasDefaultValue ? parameters[i].DefaultValue : default;
}
else
{
- if (parameters[i].ParameterType.IsPrimitive || parameters[i].ParameterType == typeof(string))
+ if (parameters[i].IsDefined(typeof(DependencyInjectAttribute), true))
{
- ps[i] = parameters[i].HasDefaultValue ? parameters[i].DefaultValue : default;
+ var attribute = parameters[i].GetCustomAttribute();
+ var type = attribute.Type ?? parameters[i].ParameterType;
+ ps[i] = this.Resolve(type, attribute.Key);
}
else
{
- if (parameters[i].IsDefined(typeof(DependencyInjectAttribute), true))
- {
- var attribute = parameters[i].GetCustomAttribute();
- var type = attribute.Type ?? parameters[i].ParameterType;
- ps[i] = this.Resolve(type, default, attribute.Key);
- }
- else
- {
- ps[i] = this.Resolve(parameters[i].ParameterType, null);
- }
+ ps[i] = this.Resolve(parameters[i].ParameterType, null);
}
}
}
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/Dependency/ContainerExtension.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/Dependency/ContainerExtension.cs
index 1b499954d..255261124 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/Dependency/ContainerExtension.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/Dependency/ContainerExtension.cs
@@ -381,35 +381,11 @@ namespace ThingsGateway.Foundation.Core
///
///
///
- ///
///
///
- public static T Resolve(this IContainer container, object[] ps, string key = "")
+ public static T Resolve(this IContainer container, string key = "")
{
- return (T)container.Resolve(typeof(T), ps, key);
- }
-
- ///
- /// 创建类型对应的实例
- ///
- ///
- ///
- ///
- public static T Resolve(this IContainer container)
- {
- return Resolve(container, null);
- }
-
- ///
- /// 创建类型对应的实例
- ///
- ///
- ///
- ///
- ///
- public static T Resolve(this IContainer container, string key)
- {
- return Resolve(container, null, key);
+ return (T)container.Resolve(typeof(T), key);
}
///
@@ -461,7 +437,7 @@ namespace ThingsGateway.Foundation.Core
{
var attribute = parameters[i].GetCustomAttribute();
var type = attribute.Type ?? parameters[i].ParameterType;
- ps[i] = container.Resolve(type, default, attribute.Key);
+ ps[i] = container.Resolve(type, attribute.Key);
}
else
{
@@ -489,47 +465,22 @@ namespace ThingsGateway.Foundation.Core
return (T)ResolveWithoutRoot(container, typeof(T));
}
- ///
- /// 尝试创建类型对应的实例,如果类型没有注册,则会返回null或者默认值类型。
- ///
- ///
- ///
- ///
- ///
- ///
- public static T TryResolve(this IContainer container, object[] ps, string key = "")
- {
- return (T)container.TryResolve(typeof(T), ps, key);
- }
-
///
/// 尝试创建类型对应的实例,如果类型没有注册,则会返回null或者默认值类型。
///
///
///
- ///
///
///
- public static object TryResolve(this IContainer container, Type fromType, object[] ps, string key = "")
+ public static object TryResolve(this IContainer container, Type fromType, string key = "")
{
if (container.IsRegistered(fromType))
{
- return container.Resolve(fromType, ps, key);
+ return container.Resolve(fromType, key);
}
return default;
}
- ///
- /// 尝试创建类型对应的实例,如果类型没有注册,则会返回null或者默认值类型。
- ///
- ///
- ///
- ///
- public static T TryResolve(this IContainer container)
- {
- return TryResolve(container, null);
- }
-
///
/// 尝试创建类型对应的实例,如果类型没有注册,则会返回null或者默认值类型。
///
@@ -537,9 +488,9 @@ namespace ThingsGateway.Foundation.Core
///
///
///
- public static T TryResolve(this IContainer container, string key)
+ public static T TryResolve(this IContainer container, string key = "")
{
- return TryResolve(container, null, key);
+ return (T)TryResolve(container, typeof(T), key);
}
#endregion Resolve
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/Dependency/IContainer.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/Dependency/IContainer.cs
index b1b4c276b..9469ba4db 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/Dependency/IContainer.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/Dependency/IContainer.cs
@@ -34,10 +34,9 @@ namespace ThingsGateway.Foundation.Core
/// 创建目标类型的对应实例。
///
///
- ///
///
///
- object Resolve(Type fromType, object[] ps = null, string key = "");
+ object Resolve(Type fromType, string key = "");
///
/// 判断某类型是否已经注册
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/Dependency/ManualContainer.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/Dependency/ManualContainer.cs
index 4bb373698..ac690cbb2 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/Dependency/ManualContainer.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/Dependency/ManualContainer.cs
@@ -67,13 +67,13 @@ namespace ThingsGateway.Foundation.Core
///
///
- public object Resolve(Type fromType, object[] ps = null, string key = "")
+ public object Resolve(Type fromType, string key = "")
{
if (fromType.FullName == "ThingsGateway.Foundation.Core.IContainer")
{
return this;
}
- if (this.TryResolve(fromType, out var instance, ps, key))
+ if (this.TryResolve(fromType, out var instance, key))
{
return instance;
}
@@ -100,10 +100,9 @@ namespace ThingsGateway.Foundation.Core
///
///
///
- ///
///
///
- protected virtual bool TryResolve(Type fromType, out object instance, object[] ps = null, string key = "")
+ protected virtual bool TryResolve(Type fromType, out object instance, string key = "")
{
if (key.IsNullOrEmpty())
{
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/Extensions/TaskExtension.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/Extensions/TaskExtension.cs
index 347fdce9d..12e647418 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/Extensions/TaskExtension.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/Extensions/TaskExtension.cs
@@ -22,6 +22,7 @@
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
+
namespace ThingsGateway.Foundation.Core
{
///
@@ -29,5 +30,24 @@ namespace ThingsGateway.Foundation.Core
///
public static class TaskExtension
{
+ ///
+ /// 同步获取配置ConfigureAwait为false时的结果。
+ ///
+ ///
+ ///
+ ///
+ public static T GetFalseAwaitResult(this Task task)
+ {
+ return task.ConfigureAwait(false).GetAwaiter().GetResult();
+ }
+
+ ///
+ /// 同步配置ConfigureAwait为false时的执行。
+ ///
+ ///
+ public static void GetFalseAwaitResult(this Task task)
+ {
+ task.ConfigureAwait(false).GetAwaiter().GetResult();
+ }
}
}
\ No newline at end of file
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/Plugins/IPlugin.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/Plugins/IPlugin.cs
index a9560a008..22b6b9c12 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/Plugins/IPlugin.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/Plugins/IPlugin.cs
@@ -30,14 +30,6 @@ namespace ThingsGateway.Foundation.Core
///
public interface IPlugin : IDisposable
{
- ///
- /// 插件执行顺序
- /// 该属性值越大,越靠前执行。值相等时,按添加先后顺序
- /// 该属性效果,仅在之前设置有效。
- ///
- [Obsolete("该属性已被弃用,插件顺序将直接由添加顺序决定。本设置将在正式版发布时直接删除", true)]
- int Order { get; set; }
-
///
/// 在插件被成功添加在时执行。
///
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/Plugins/PluginBase.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/Plugins/PluginBase.cs
index 432213d56..f5bc0520e 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/Plugins/PluginBase.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/Plugins/PluginBase.cs
@@ -17,9 +17,6 @@ namespace ThingsGateway.Foundation.Core
///
public class PluginBase : DisposableObject, IPlugin
{
- ///
- [Obsolete("该属性已被弃用,插件顺序将直接由添加顺序决定。本设置将在正式版发布时直接删除", true)]
- public int Order { get; set; }
///
protected virtual void Loaded(IPluginsManager pluginsManager)
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/Common/Locker.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/Threading/Locker.cs
similarity index 100%
rename from framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/Common/Locker.cs
rename to framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/Threading/Locker.cs
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Dmtp/Components/Http/HttpDmtpClient.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Dmtp/Components/Http/HttpDmtpClient.cs
index 60849010a..7518df21c 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Dmtp/Components/Http/HttpDmtpClient.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Dmtp/Components/Http/HttpDmtpClient.cs
@@ -184,7 +184,7 @@ namespace ThingsGateway.Foundation.Dmtp
}
if (!this.Online)
{
- await base.ConnectAsync(timeout);
+ await base.ConnectAsync(timeout, token);
}
var request = new HttpRequest()
@@ -223,20 +223,20 @@ namespace ThingsGateway.Foundation.Dmtp
}
///
- protected override bool HandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo)
+ protected override async Task ReceivedData(ReceivedDataEventArgs e)
{
- if (this.Protocol == DmtpUtility.DmtpProtocol && requestInfo is DmtpMessage message)
+ if (this.Protocol == DmtpUtility.DmtpProtocol && e.RequestInfo is DmtpMessage message)
{
if (!this.m_smtpActor.InputReceivedData(message))
{
if (this.PluginsManager.Enable)
{
- this.PluginsManager.Raise(nameof(IDmtpReceivedPlugin.OnDmtpReceived), this, new DmtpMessageEventArgs(message));
+ await this.PluginsManager.RaiseAsync(nameof(IDmtpReceivedPlugin.OnDmtpReceived), this, new DmtpMessageEventArgs(message));
}
}
- return false;
+ return;
}
- return base.HandleReceivedData(byteBlock, requestInfo);
+ await base.ReceivedData(e);
}
///
@@ -251,9 +251,9 @@ namespace ThingsGateway.Foundation.Dmtp
}
///
- protected override void OnDisconnected(DisconnectEventArgs e)
+ protected override async Task OnDisconnected(DisconnectEventArgs e)
{
- base.OnDisconnected(e);
+ await base.OnDisconnected(e);
this.DmtpActor.Close(false, e.Message);
}
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Dmtp/Components/Http/HttpDmtpService.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Dmtp/Components/Http/HttpDmtpService.cs
index 2d9af9731..fe2bdd436 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Dmtp/Components/Http/HttpDmtpService.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Dmtp/Components/Http/HttpDmtpService.cs
@@ -62,10 +62,10 @@ namespace ThingsGateway.Foundation.Dmtp
}
///
- protected override void OnConnected(TClient socketClient, ConnectedEventArgs e)
+ protected override async Task OnConnected(TClient socketClient, ConnectedEventArgs e)
{
socketClient.m_internalOnRpcActorInit = this.PrivateOnRpcActorInit;
- base.OnConnected(socketClient, e);
+ await base.OnConnected(socketClient, e);
}
private IDmtpActor OnServiceFindDmtpActor(string id)
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Dmtp/Components/Http/HttpDmtpSocketClient.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Dmtp/Components/Http/HttpDmtpSocketClient.cs
index 824b0a719..59f4d7dd8 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Dmtp/Components/Http/HttpDmtpSocketClient.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Dmtp/Components/Http/HttpDmtpSocketClient.cs
@@ -96,42 +96,55 @@ namespace ThingsGateway.Foundation.Dmtp
base.Dispose(disposing);
}
+ /////
+ //protected override bool HandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo)
+ //{
+ // if (this.Protocol == DmtpUtility.DmtpProtocol && requestInfo is DmtpMessage message)
+ // {
+ // if (!this.m_smtpActor.InputReceivedData(message))
+ // {
+ // if (this.PluginsManager.Enable)
+ // {
+ // this.PluginsManager.Raise(nameof(IDmtpReceivedPlugin.OnDmtpReceived), this, new DmtpMessageEventArgs(message));
+ // }
+ // }
+
+ // return false;
+ // }
+ // else
+ // {
+ // return base.HandleReceivedData(byteBlock, requestInfo);
+ // }
+ //}
+
///
- protected override bool HandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo)
+ protected override async Task ReceivedData(ReceivedDataEventArgs e)
{
- if (this.Protocol == DmtpUtility.DmtpProtocol && requestInfo is DmtpMessage message)
+ if (this.Protocol == DmtpUtility.DmtpProtocol && e.RequestInfo is DmtpMessage message)
{
if (!this.m_smtpActor.InputReceivedData(message))
{
- if (this.PluginsManager.Enable)
- {
- this.PluginsManager.Raise(nameof(IDmtpReceivedPlugin.OnDmtpReceived), this, new DmtpMessageEventArgs(message));
- }
+ await this.PluginsManager.RaiseAsync(nameof(IDmtpReceivedPlugin.OnDmtpReceived), this, new DmtpMessageEventArgs(message));
}
-
- return false;
- }
- else
- {
- return base.HandleReceivedData(byteBlock, requestInfo);
}
+ await base.ReceivedData(e);
}
///
///
///
///
- protected override void OnDisconnected(DisconnectEventArgs e)
+ protected override async Task OnDisconnected(DisconnectEventArgs e)
{
this.DmtpActor?.Close(false, e.Message);
- base.OnDisconnected(e);
+ await base.OnDisconnected(e);
}
///
///
///
///
- protected override void OnReceivedHttpRequest(HttpRequest request)
+ protected override async Task OnReceivedHttpRequest(HttpRequest request)
{
if (request.IsMethod(DmtpUtility.Dmtp) && request.IsUpgrade() &&
string.Equals(request.Headers.Get(HttpHeaders.Upgrade), DmtpUtility.Dmtp, StringComparison.OrdinalIgnoreCase))
@@ -142,7 +155,7 @@ namespace ThingsGateway.Foundation.Dmtp
this.DefaultSend(new HttpResponse().SetStatus(101, "Switching Protocols").BuildAsBytes());
return;
}
- base.OnReceivedHttpRequest(request);
+ await base.OnReceivedHttpRequest(request);
}
private void SetRpcActor(DmtpActor actor)
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Dmtp/Components/TCP/TcpDmtpClient.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Dmtp/Components/TCP/TcpDmtpClient.cs
index 4f49188f2..1f220a7ae 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Dmtp/Components/TCP/TcpDmtpClient.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Dmtp/Components/TCP/TcpDmtpClient.cs
@@ -38,23 +38,24 @@ namespace ThingsGateway.Foundation.Dmtp
this.Protocol = DmtpUtility.DmtpProtocol;
}
+ ///
+ public IDmtpActor DmtpActor { get => this.m_smtpActor; }
+
///
public string Id => this.DmtpActor.Id;
#region 字段
+ private readonly SemaphoreSlim m_semaphore = new SemaphoreSlim(1, 1);
private bool m_allowRoute;
private Func m_findDmtpActor;
private SealedDmtpActor m_smtpActor;
- private readonly SemaphoreSlim m_semaphore = new SemaphoreSlim(1, 1);
+
#endregion 字段
///
public bool IsHandshaked => this.DmtpActor != null && this.DmtpActor.IsHandshaked;
- ///
- public IDmtpActor DmtpActor { get => this.m_smtpActor; }
-
///
/// 发送关闭消息。
///
@@ -153,7 +154,7 @@ namespace ThingsGateway.Foundation.Dmtp
}
if (!this.Online)
{
- await base.ConnectAsync(timeout);
+ await base.ConnectAsync(timeout, token);
}
await this.m_smtpActor.HandshakeAsync(this.Config.GetValue(DmtpConfigExtension.VerifyTokenProperty),
@@ -235,20 +236,6 @@ namespace ThingsGateway.Foundation.Dmtp
base.Dispose(disposing);
}
- ///
- protected override bool HandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo)
- {
- var message = (DmtpMessage)requestInfo;
- if (!this.m_smtpActor.InputReceivedData(message))
- {
- if (this.PluginsManager.Enable)
- {
- this.PluginsManager.Raise(nameof(IDmtpReceivedPlugin.OnDmtpReceived), this, new DmtpMessageEventArgs(message));
- }
- }
- return false;
- }
-
///
protected override void LoadConfig(TouchSocketConfig config)
{
@@ -274,14 +261,31 @@ namespace ThingsGateway.Foundation.Dmtp
}
///
- protected override void OnDisconnected(DisconnectEventArgs e)
+ protected override async Task OnDisconnected(DisconnectEventArgs e)
{
- base.OnDisconnected(e);
+ await base.OnDisconnected(e);
this.DmtpActor.Close(false, e.Message);
}
+ ///
+ protected override async Task ReceivedData(ReceivedDataEventArgs e)
+ {
+ var message = (DmtpMessage)e.RequestInfo;
+ if (!this.m_smtpActor.InputReceivedData(message))
+ {
+ await this.PluginsManager.RaiseAsync(nameof(IDmtpReceivedPlugin.OnDmtpReceived), this, new DmtpMessageEventArgs(message));
+ }
+
+ await base.ReceivedData(e);
+ }
+
#region 内部委托绑定
+ private void DmtpActorSend(DmtpActor actor, ArraySegment[] transferBytes)
+ {
+ base.Send(transferBytes);
+ }
+
private void OnDmtpActorClose(DmtpActor actor, string msg)
{
base.Close(msg);
@@ -330,11 +334,6 @@ namespace ThingsGateway.Foundation.Dmtp
this.OnRouting(e);
}
- private void DmtpActorSend(DmtpActor actor, ArraySegment[] transferBytes)
- {
- base.Send(transferBytes);
- }
-
#endregion 内部委托绑定
#region 事件触发
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Dmtp/Components/TCP/TcpDmtpService.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Dmtp/Components/TCP/TcpDmtpService.cs
index 2d153ac2d..d40d998f0 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Dmtp/Components/TCP/TcpDmtpService.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Dmtp/Components/TCP/TcpDmtpService.cs
@@ -68,14 +68,14 @@ namespace ThingsGateway.Foundation.Dmtp
///
///
///
- protected override void OnConnecting(TClient socketClient, ConnectingEventArgs e)
+ protected override async Task OnConnecting(TClient socketClient, ConnectingEventArgs e)
{
socketClient.SetDmtpActor(new SealedDmtpActor(this.m_allowRoute)
{
Id = e.Id,
OnFindDmtpActor = this.m_allowRoute ? (this.m_findDmtpActor ?? this.OnServiceFindDmtpActor) : null
});
- base.OnConnecting(socketClient, e);
+ await base.OnConnecting(socketClient, e);
}
private IDmtpActor OnServiceFindDmtpActor(string id)
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Dmtp/Components/TCP/TcpDmtpSocketClient.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Dmtp/Components/TCP/TcpDmtpSocketClient.cs
index ee0d3e66e..17708afb4 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Dmtp/Components/TCP/TcpDmtpSocketClient.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Dmtp/Components/TCP/TcpDmtpSocketClient.cs
@@ -40,12 +40,12 @@ namespace ThingsGateway.Foundation.Dmtp
this.Protocol = DmtpUtility.DmtpProtocol;
}
- ///
- public bool IsHandshaked => this.DmtpActor != null && this.DmtpActor.IsHandshaked;
-
///
public IDmtpActor DmtpActor { get => this.m_smtpActor; }
+ ///
+ public bool IsHandshaked => this.DmtpActor != null && this.DmtpActor.IsHandshaked;
+
///
/// 验证超时时间,默认为3000ms
///
@@ -201,26 +201,23 @@ namespace ThingsGateway.Foundation.Dmtp
}
///
- protected override bool HandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo)
+ protected override async Task ReceivedData(ReceivedDataEventArgs e)
{
- var message = (DmtpMessage)requestInfo;
+ var message = (DmtpMessage)e.RequestInfo;
if (!this.m_smtpActor.InputReceivedData(message))
{
- if (this.PluginsManager.Enable)
- {
- this.PluginsManager.Raise(nameof(IDmtpReceivedPlugin.OnDmtpReceived), this, new DmtpMessageEventArgs(message));
- }
+ await this.PluginsManager.RaiseAsync(nameof(IDmtpReceivedPlugin.OnDmtpReceived), this, new DmtpMessageEventArgs(message));
}
- return false;
+ await base.ReceivedData(e);
}
///
- protected override void OnConnected(ConnectedEventArgs e)
+ protected override async Task OnConnected(ConnectedEventArgs e)
{
this.m_smtpActor.Id = this.Id;
- base.OnConnected(e);
+ await base.OnConnected(e);
- Task.Run(async () =>
+ _ = Task.Run(async () =>
{
await Task.Delay(this.VerifyTimeout);
if (!this.IsHandshaked)
@@ -232,15 +229,10 @@ namespace ThingsGateway.Foundation.Dmtp
}
///
- protected override void OnDisconnected(DisconnectEventArgs e)
+ protected override async Task OnDisconnected(DisconnectEventArgs e)
{
this.DmtpActor.Close(false, e.Message);
- base.OnDisconnected(e);
- }
-
- private void ThisOnResetId(DmtpActor rpcActor, WaitSetId waitSetId)
- {
- this.DirectResetId(waitSetId.NewId);
+ await base.OnDisconnected(e);
}
private void ThisDmtpActorOutputSend(DmtpActor actor, ArraySegment[] transferBytes)
@@ -248,6 +240,11 @@ namespace ThingsGateway.Foundation.Dmtp
base.Send(transferBytes);
}
+ private void ThisOnResetId(DmtpActor rpcActor, WaitSetId waitSetId)
+ {
+ this.DirectResetId(waitSetId.NewId);
+ }
+
#region 发送
///
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Dmtp/Components/Udp/UdpDmtp.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Dmtp/Components/Udp/UdpDmtp.cs
index 308d4007e..c5b5bd764 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Dmtp/Components/Udp/UdpDmtp.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Dmtp/Components/Udp/UdpDmtp.cs
@@ -75,20 +75,20 @@ namespace ThingsGateway.Foundation.Dmtp.Rpc
}
///
- protected override void HandleReceivedData(EndPoint remoteEndPoint, ByteBlock byteBlock, IRequestInfo requestInfo)
+ protected override async Task ReceivedData(UdpReceivedDataEventArgs e)
{
- var client = this.PrivateGetUdpDmtpClient(remoteEndPoint);
+ var client = this.PrivateGetUdpDmtpClient(e.EndPoint);
if (client == null)
{
return;
}
- var message = DmtpMessage.CreateFrom(byteBlock);
+ var message = DmtpMessage.CreateFrom(e.ByteBlock);
if (!client.InputReceivedData(message))
{
if (this.PluginsManager.Enable)
{
- this.PluginsManager.Raise(nameof(IDmtpReceivedPlugin.OnDmtpReceived), client, new DmtpMessageEventArgs(message));
+ await this.PluginsManager.RaiseAsync(nameof(IDmtpReceivedPlugin.OnDmtpReceived), client, new DmtpMessageEventArgs(message));
}
}
}
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Dmtp/Components/WebSocket/WebSocketDmtpClient.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Dmtp/Components/WebSocket/WebSocketDmtpClient.cs
index 93e53db4f..4b7eea4bc 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Dmtp/Components/WebSocket/WebSocketDmtpClient.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Dmtp/Components/WebSocket/WebSocketDmtpClient.cs
@@ -49,9 +49,7 @@ namespace ThingsGateway.Foundation.Dmtp
}
#region 字段
-#pragma warning disable CS0414
- private bool m_allowRoute;
-#pragma warning restore CS0414
+
private ClientWebSocket m_client;
private Func m_findDmtpActor;
private ValueCounter m_receiveCounter;
@@ -236,18 +234,6 @@ namespace ThingsGateway.Foundation.Dmtp
this.DmtpActor.ResetId(newId);
}
- ///
- /// 配置
- ///
- ///
- ///
- public IWebSocketDmtpClient Setup(string ipHost)
- {
- var config = new TouchSocketConfig();
- config.SetRemoteIPHost(new IPHost(ipHost));
- return this.Setup(config);
- }
-
///
/// 配置
///
@@ -297,7 +283,6 @@ namespace ThingsGateway.Foundation.Dmtp
if (this.Container.IsRegistered(typeof(IDmtpRouteService)))
{
- this.m_allowRoute = true;
this.m_findDmtpActor = this.Container.Resolve().FindDmtpActor;
}
}
@@ -421,10 +406,7 @@ namespace ThingsGateway.Foundation.Dmtp
var message = (DmtpMessage)requestInfo;
if (!this.m_dmtpActor.InputReceivedData(message))
{
- if (this.PluginsManager.Enable)
- {
- this.PluginsManager.Raise(nameof(IDmtpReceivedPlugin.OnDmtpReceived), this, new DmtpMessageEventArgs(message));
- }
+ this.PluginsManager.Raise(nameof(IDmtpReceivedPlugin.OnDmtpReceived), this, new DmtpMessageEventArgs(message));
}
}
@@ -534,5 +516,28 @@ namespace ThingsGateway.Foundation.Dmtp
}
#endregion 事件触发
+
+ #region Receiver
+
+ ///
+ /// 不支持该功能
+ ///
+ ///
+ ///
+ public IReceiver CreateReceiver()
+ {
+ throw new NotSupportedException("不支持该功能");
+ }
+
+ ///
+ /// 不支持该功能
+ ///
+ ///
+ public void ClearReceiver()
+ {
+ throw new NotSupportedException("不支持该功能");
+ }
+
+ #endregion
}
}
\ No newline at end of file
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Dmtp/Features/FileTransfer/Actor/DmtpFileTransferActor.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Dmtp/Features/FileTransfer/Actor/DmtpFileTransferActor.cs
index 80fbc1162..17482521b 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Dmtp/Features/FileTransfer/Actor/DmtpFileTransferActor.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Dmtp/Features/FileTransfer/Actor/DmtpFileTransferActor.cs
@@ -1507,7 +1507,7 @@ namespace ThingsGateway.Foundation.Dmtp.FileTransfer
waitFileSection.Message = ex.Message;
}
- waitFileSection.Value.Dispose();
+ waitFileSection.Value.SafeDispose();
waitFileSection.Value = default;
using (var byteBlock = new ByteBlock())
{
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/Components/HttpClient.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/Components/HttpClient.cs
index 41629af51..2b087df15 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/Components/HttpClient.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/Components/HttpClient.cs
@@ -213,14 +213,11 @@ namespace ThingsGateway.Foundation.Http
base.Dispose(disposing);
}
- ///
+
///
- ///
- ///
- ///
- protected override bool HandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo)
+ protected override Task ReceivedData(ReceivedDataEventArgs e)
{
- if (requestInfo is HttpResponse response)
+ if (e.RequestInfo is HttpResponse response)
{
if (this.m_getContent)
{
@@ -229,18 +226,18 @@ namespace ThingsGateway.Foundation.Http
this.m_waitData.Set(response);
}
- return false;
+ return base.ReceivedData(e);
}
///
///
///
///
- protected override void OnConnecting(ConnectingEventArgs e)
+ protected override async Task OnConnecting(ConnectingEventArgs e)
{
this.Protocol = Protocol.Http;
this.SetDataHandlingAdapter(new HttpClientDataHandlingAdapter());
- base.OnConnecting(e);
+ await base.OnConnecting(e);
}
}
}
\ No newline at end of file
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/Components/HttpClientSlim.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/Components/HttpClientSlim.cs
index f749387de..81238a441 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/Components/HttpClientSlim.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/Components/HttpClientSlim.cs
@@ -20,6 +20,8 @@ using System.Threading.Tasks;
using ThingsGateway.Foundation.Core;
using ThingsGateway.Foundation.Sockets;
+using HttpClient = System.Net.Http.HttpClient;
+using HttpMethod = System.Net.Http.HttpMethod;
namespace ThingsGateway.Foundation.Http
{
@@ -100,16 +102,6 @@ namespace ThingsGateway.Foundation.Http
return this;
}
- ///
- /// 配置
- ///
- ///
- ///
- public HttpClientSlim Setup(string remoteIPHost)
- {
- return this.Setup(new TouchSocketConfig().SetRemoteIPHost(remoteIPHost));
- }
-
private void BuildConfig(TouchSocketConfig config)
{
this.Config = config;
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/Components/HttpSocketClient.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/Components/HttpSocketClient.cs
index 01514558d..49e1cc224 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/Components/HttpSocketClient.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/Components/HttpSocketClient.cs
@@ -39,34 +39,35 @@ namespace ThingsGateway.Foundation.Http
}
///
- protected override void OnConnecting(ConnectingEventArgs e)
+ protected override async Task OnConnecting(ConnectingEventArgs e)
{
this.SetDataHandlingAdapter(new HttpServerDataHandlingAdapter());
- base.OnConnecting(e);
+ await base.OnConnecting(e);
}
///
- protected override bool HandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo)
+ protected override async Task ReceivedData(ReceivedDataEventArgs e)
{
- if (requestInfo is HttpRequest request)
+ if (e.RequestInfo is HttpRequest request)
{
- this.OnReceivedHttpRequest(request);
+ await this.OnReceivedHttpRequest(request);
}
-
- return false;
+ await base.ReceivedData(e);
}
///
/// 当收到到Http请求时。覆盖父类方法将不会触发插件。
///
- protected virtual void OnReceivedHttpRequest(HttpRequest request)
+ protected virtual Task OnReceivedHttpRequest(HttpRequest request)
{
if (this.PluginsManager.GetPluginCount(nameof(IHttpPlugin.OnHttpRequest)) > 0)
{
var e = new HttpContextEventArgs(new HttpContext(request));
- this.PluginsManager.Raise(nameof(IHttpPlugin.OnHttpRequest), this, e);
+ return this.PluginsManager.RaiseAsync(nameof(IHttpPlugin.OnHttpRequest), this, e);
}
+
+ return EasyTask.CompletedTask;
}
}
}
\ No newline at end of file
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/Plugins/Interfaces/IHttpDeletePlugin.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/Plugins/Interfaces/IHttpDeletePlugin.cs
deleted file mode 100644
index 5ac418583..000000000
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/Plugins/Interfaces/IHttpDeletePlugin.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-#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
-{
- ///
- /// IHttpDeletePlugin
- ///
- [Obsolete("该插件已被弃用,请考虑使用“IHttpPlugin”插件代替使用。本插件将在正式版发布时直接移除。", true)]
- public interface IHttpDeletePlugin : IPlugin where TClient : IHttpSocketClient
- {
- ///
- /// 在收到Delete时
- ///
- ///
- ///
- ///
- Task OnHttpDelete(TClient client, HttpContextEventArgs e);
- }
-
- ///
- /// IHttpDeletePlugin
- ///
- [Obsolete("该插件已被弃用,请考虑使用“IHttpPlugin”插件代替使用。本插件将在正式版发布时直接移除。", true)]
- public interface IHttpDeletePlugin : IHttpDeletePlugin
- {
- }
-}
\ No newline at end of file
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/Plugins/Interfaces/IHttpGetPlugin.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/Plugins/Interfaces/IHttpGetPlugin.cs
deleted file mode 100644
index c186f0721..000000000
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/Plugins/Interfaces/IHttpGetPlugin.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-#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
-{
- ///
- /// IHttpGetPlugin
- ///
- [Obsolete("该插件已被弃用,请考虑使用“IHttpPlugin”插件代替使用。本插件将在正式版发布时直接移除。", true)]
- public interface IHttpGetPlugin : IPlugin where TClient : IHttpSocketClient
- {
- ///
- /// 在收到Get时
- ///
- ///
- ///
- ///
- Task OnHttpGet(TClient client, HttpContextEventArgs e);
- }
-
- ///
- /// IHttpGetPlugin
- ///
- [Obsolete("该插件已被弃用,请考虑使用“IHttpPlugin”插件代替使用。本插件将在正式版发布时直接移除。", true)]
- public interface IHttpGetPlugin : IHttpGetPlugin
- {
- }
-}
\ No newline at end of file
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/Plugins/Interfaces/IHttpPlugin.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/Plugins/Interfaces/IHttpPlugin.cs
index 06e577a96..56182f61b 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/Plugins/Interfaces/IHttpPlugin.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/Plugins/Interfaces/IHttpPlugin.cs
@@ -31,8 +31,7 @@ namespace ThingsGateway.Foundation.Http
public interface IHttpPlugin : IPlugin where TClient : IHttpSocketClient
{
///
- /// 在收到Http请求时。注意:此插件的执行在,,
- /// ,之前。
+ /// 在收到Http请求时
///
///
///
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/Plugins/Interfaces/IHttpPostPlugin.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/Plugins/Interfaces/IHttpPostPlugin.cs
deleted file mode 100644
index f88361ea2..000000000
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/Plugins/Interfaces/IHttpPostPlugin.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-#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
-{
- ///
- /// IHttpPostPlugin
- ///
- [Obsolete("该插件已被弃用,请考虑使用“IHttpPlugin”插件代替使用。本插件将在正式版发布时直接移除。", true)]
- public interface IHttpPostPlugin : IPlugin where TClient : IHttpSocketClient
- {
- ///
- /// 在收到Post时
- ///
- ///
- ///
- ///
- Task OnHttpPost(TClient client, HttpContextEventArgs e);
- }
-
- ///
- /// IHttpPostPlugin
- ///
- [Obsolete("该插件已被弃用,请考虑使用“IHttpPlugin”插件代替使用。本插件将在正式版发布时直接移除。", true)]
- public interface IHttpPostPlugin : IHttpPostPlugin
- {
- }
-}
\ No newline at end of file
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/WebSockets/Common/InternalWebSocket.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/WebSockets/Common/InternalWebSocket.cs
index b81239a2c..909a18bbf 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/WebSockets/Common/InternalWebSocket.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/WebSockets/Common/InternalWebSocket.cs
@@ -75,7 +75,17 @@ namespace ThingsGateway.Foundation.Http.WebSockets
await this.m_resetEventForRead.WaitOneAsync(token);
return new WebSocketReceiveResult(this.ComplateRead, this.m_dataFrame);
}
-
+#if NET6_0_OR_GREATER
+ public async ValueTask ValueReadAsync(CancellationToken token)
+ {
+ if (!this.m_receive)
+ {
+ return new WebSocketReceiveResult(this.ComplateRead, null);
+ }
+ await this.m_resetEventForRead.WaitOneAsync(token);
+ return new WebSocketReceiveResult(this.ComplateRead, this.m_dataFrame);
+ }
+#endif
#region 发送
public void Send(WSDataFrame dataFrame, bool endOfMessage = true)
{
@@ -145,7 +155,7 @@ namespace ThingsGateway.Foundation.Http.WebSockets
protected override void Dispose(bool disposing)
{
- this.m_client.RemoveValue(WebSocketClientExtensions.WebSocketProperty);
+ this.m_client.RemoveValue(WebSocketClientExtension.WebSocketProperty);
this.m_resetEventForComplateRead.SafeDispose();
this.m_resetEventForRead.SafeDispose();
this.m_dataFrame = null;
@@ -154,8 +164,8 @@ namespace ThingsGateway.Foundation.Http.WebSockets
private void ComplateRead()
{
- this.m_resetEventForComplateRead.Set();
this.m_dataFrame = default;
+ this.m_resetEventForComplateRead.Set();
}
}
}
\ No newline at end of file
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/WebSockets/Common/WebSocketReceiveResult.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/WebSockets/Common/WebSocketReceiveResult.cs
index 7d681abd2..5ba7cb48c 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/WebSockets/Common/WebSocketReceiveResult.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/WebSockets/Common/WebSocketReceiveResult.cs
@@ -41,5 +41,10 @@ namespace ThingsGateway.Foundation.Http.WebSockets
/// WebSocket数据帧
///
public WSDataFrame DataFrame { get; private set; }
+
+ ///
+ /// 连接已关闭
+ ///
+ public bool IsClosed => this.DataFrame == null;
}
}
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/WebSockets/Components/WebSocketClient.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/WebSockets/Components/WebSocketClient.cs
index d8b43ec98..ca5b9a078 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/WebSockets/Components/WebSocketClient.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/WebSockets/Components/WebSocketClient.cs
@@ -39,10 +39,14 @@ namespace ThingsGateway.Foundation.Http.WebSockets
///
///
///
- protected override void OnHandleWSDataFrame(WSDataFrame dataFrame)
+ protected override async Task OnReceivedWSDataFrame(WSDataFrame dataFrame)
{
- this.Received?.Invoke(this, dataFrame);
- base.OnHandleWSDataFrame(dataFrame);
+ if (this.Received != null)
+ {
+ await this.Received.Invoke(this, dataFrame);
+ }
+
+ await base.OnReceivedWSDataFrame(dataFrame);
}
}
@@ -211,20 +215,44 @@ namespace ThingsGateway.Foundation.Http.WebSockets
#endregion 事件
+ /////
+ //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;
+ //}
+
///
- protected override bool HandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo)
+ protected override async Task ReceivedData(ReceivedDataEventArgs e)
{
if (this.GetHandshaked())
{
- var dataFrame = (WSDataFrame)requestInfo;
- this.OnHandleWSDataFrame(dataFrame);
+ var dataFrame = (WSDataFrame)e.RequestInfo;
+ await this.OnReceivedWSDataFrame(dataFrame);
}
else
{
- if (requestInfo is HttpResponse response)
+ if (e.RequestInfo is HttpResponse response)
{
response.Flag = false;
- base.HandleReceivedData(byteBlock, requestInfo);
+ await base.ReceivedData(e);
SpinWait.SpinUntil(() =>
{
return (bool)response.Flag;
@@ -232,32 +260,32 @@ namespace ThingsGateway.Foundation.Http.WebSockets
}
}
- return false;
+ await base.ReceivedData(e);
}
///
///
///
///
- protected override void OnDisconnected(DisconnectEventArgs e)
+ protected override async Task OnDisconnected(DisconnectEventArgs e)
{
this.SetValue(WebSocketFeature.HandshakedProperty, false);
- if (this.TryGetValue(WebSocketClientExtensions.WebSocketProperty, out var internalWebSocket))
+ if (this.TryGetValue(WebSocketClientExtension.WebSocketProperty, out var internalWebSocket))
{
_ = internalWebSocket.TryInputReceiveAsync(null);
}
- base.OnDisconnected(e);
+ await base.OnDisconnected(e);
}
///
/// 当收到WS数据时。
///
///
- protected virtual void OnHandleWSDataFrame(WSDataFrame dataFrame)
+ protected virtual async Task OnReceivedWSDataFrame(WSDataFrame dataFrame)
{
- if (this.TryGetValue(WebSocketClientExtensions.WebSocketProperty, out var internalWebSocket))
+ if (this.TryGetValue(WebSocketClientExtension.WebSocketProperty, out var internalWebSocket))
{
- if (internalWebSocket.TryInputReceiveAsync(dataFrame).ConfigureAwait(false).GetAwaiter().GetResult())
+ if (await internalWebSocket.TryInputReceiveAsync(dataFrame))
{
return;
}
@@ -265,7 +293,7 @@ namespace ThingsGateway.Foundation.Http.WebSockets
if (this.PluginsManager.Enable)
{
- this.PluginsManager.Raise(nameof(IWebSocketReceivedPlugin.OnWebSocketReceived), this, new WSDataFrameEventArgs(dataFrame));
+ await this.PluginsManager.RaiseAsync(nameof(IWebSocketReceivedPlugin.OnWebSocketReceived), this, new WSDataFrameEventArgs(dataFrame));
}
}
}
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/WebSockets/DataAdapter/WebSocketDataHandlingAdapter.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/WebSockets/DataAdapter/WebSocketDataHandlingAdapter.cs
index 4cccd6ce5..bf749c184 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/WebSockets/DataAdapter/WebSocketDataHandlingAdapter.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/WebSockets/DataAdapter/WebSocketDataHandlingAdapter.cs
@@ -28,7 +28,7 @@ namespace ThingsGateway.Foundation.Http.WebSockets
///
/// WebSocket适配器
///
- public class WebSocketDataHandlingAdapter : SingleStreamDataHandlingAdapter
+ public sealed class WebSocketDataHandlingAdapter : SingleStreamDataHandlingAdapter
{
private WSDataFrame m_dataFrameTemp;
@@ -42,16 +42,6 @@ namespace ThingsGateway.Foundation.Http.WebSockets
///
private ByteBlock m_tempByteBlock;
- ///
- ///
- ///
- public override bool CanSendRequestInfo => false;
-
- ///
- ///
- ///
- public override bool CanSplicingSend => false;
-
///
/// 解码
///
@@ -183,35 +173,6 @@ namespace ThingsGateway.Foundation.Http.WebSockets
}
}
- ///
- /// 当发送数据前处理数据
- ///
- ///
- ///
- ///
- protected override void PreviewSend(byte[] buffer, int offset, int length)
- {
- this.GoSend(buffer, offset, length);
- }
-
- ///
- ///
- ///
- ///
- protected override void PreviewSend(IList> transferBytes)
- {
- throw new System.NotImplementedException();//因为设置了不支持拼接发送,所以该方法可以不实现。
- }
-
- ///
- ///
- ///
- ///
- protected override void PreviewSend(IRequestInfo requestInfo)
- {
- throw new NotImplementedException();
- }
-
///
///
///
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/WebSockets/DelegateCollection.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/WebSockets/DelegateCollection.cs
index acea55482..c32afe367 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/WebSockets/DelegateCollection.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/WebSockets/DelegateCollection.cs
@@ -30,5 +30,5 @@ namespace ThingsGateway.Foundation.Http.WebSockets
///
///
///
- public delegate void WSDataFrameEventHandler(TClient client, WSDataFrame dataFrame);
+ public delegate Task WSDataFrameEventHandler(TClient client, WSDataFrame dataFrame);
}
\ No newline at end of file
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/WebSockets/Extensions/WebSocketClientExtensions.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/WebSockets/Extensions/WebSocketClientExtension.cs
similarity index 99%
rename from framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/WebSockets/Extensions/WebSocketClientExtensions.cs
rename to framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/WebSockets/Extensions/WebSocketClientExtension.cs
index efaea5180..9be29ad14 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/WebSockets/Extensions/WebSocketClientExtensions.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/WebSockets/Extensions/WebSocketClientExtension.cs
@@ -28,7 +28,7 @@ namespace ThingsGateway.Foundation.Http.WebSockets
///
/// WSClientExtensions
///
- public static class WebSocketClientExtensions
+ public static class WebSocketClientExtension
{
#region DependencyProperty
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/WebSockets/Config/WebSocketConfigExtensions.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/WebSockets/Extensions/WebSocketConfigExtension.cs
similarity index 98%
rename from framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/WebSockets/Config/WebSocketConfigExtensions.cs
rename to framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/WebSockets/Extensions/WebSocketConfigExtension.cs
index 8291817ce..72c52ff7d 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/WebSockets/Config/WebSocketConfigExtensions.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/WebSockets/Extensions/WebSocketConfigExtension.cs
@@ -29,7 +29,7 @@ namespace ThingsGateway.Foundation.Sockets
///
/// WebSocketConfigExtensions
///
- public static class WebSocketConfigExtensions
+ public static class WebSocketConfigExtension
{
///
/// 构建WebSocketClient类客户端,并连接
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/WebSockets/Extensions/WebSocketDataFrameExtensions.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/WebSockets/Extensions/WebSocketDataFrameExtension.cs
similarity index 99%
rename from framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/WebSockets/Extensions/WebSocketDataFrameExtensions.cs
rename to framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/WebSockets/Extensions/WebSocketDataFrameExtension.cs
index a35996bea..c49d88646 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/WebSockets/Extensions/WebSocketDataFrameExtensions.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/WebSockets/Extensions/WebSocketDataFrameExtension.cs
@@ -29,7 +29,7 @@ namespace ThingsGateway.Foundation.Http.WebSockets
///
/// WSDataFrame辅助扩展类
///
- public static class WebSocketDataFrameExtensions
+ public static class WebSocketDataFrameExtension
{
///
/// 追加二进制流
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/WebSockets/Extensions/WebSocketServerExtensions.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/WebSockets/Extensions/WebSocketServerExtension.cs
similarity index 94%
rename from framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/WebSockets/Extensions/WebSocketServerExtensions.cs
rename to framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/WebSockets/Extensions/WebSocketServerExtension.cs
index 25b7f8f59..491b0c582 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/WebSockets/Extensions/WebSocketServerExtensions.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/WebSockets/Extensions/WebSocketServerExtension.cs
@@ -28,7 +28,7 @@ namespace ThingsGateway.Foundation.Http.WebSockets
///
/// WebSocketServerExtensions
///
- public static class WebSocketServerExtensions
+ public static class WebSocketServerExtension
{
///
/// 转化Protocol协议标识为
@@ -49,7 +49,8 @@ namespace ThingsGateway.Foundation.Http.WebSockets
{
IsPermitOperation = true
};
- await client.PluginsManager.RaiseAsync(nameof(IWebSocketHandshakingPlugin.OnWebSocketHandshaking), client, args);
+ await client.PluginsManager.RaiseAsync(nameof(IWebSocketHandshakingPlugin.OnWebSocketHandshaking), client, args).ConfigureAwait(false);
+
if (args.Context.Response.Responsed)
{
return false;
@@ -63,9 +64,10 @@ namespace ThingsGateway.Foundation.Http.WebSockets
using (var byteBlock = new ByteBlock())
{
args.Context.Response.Build(byteBlock);
- await client.DefaultSendAsync(byteBlock);
+ await client.DefaultSendAsync(byteBlock).ConfigureAwait(false);
}
- await client.PluginsManager.RaiseAsync(nameof(IWebSocketHandshakedPlugin.OnWebSocketHandshaked), client, new HttpContextEventArgs(httpContext));
+ await client.PluginsManager.RaiseAsync(nameof(IWebSocketHandshakedPlugin.OnWebSocketHandshaked), client, new HttpContextEventArgs(httpContext))
+ .ConfigureAwait(false);
return true;
}
else
@@ -74,7 +76,7 @@ namespace ThingsGateway.Foundation.Http.WebSockets
using (var byteBlock = new ByteBlock())
{
args.Context.Response.Build(byteBlock);
- await client.DefaultSendAsync(byteBlock);
+ await client.DefaultSendAsync(byteBlock).ConfigureAwait(false);
}
client.Close("主动拒绝WebSocket连接");
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/WebSockets/Interface/IWebSocket.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/WebSockets/Interface/IWebSocket.cs
index a3fd3ad34..2897cff84 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/WebSockets/Interface/IWebSocket.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/WebSockets/Interface/IWebSocket.cs
@@ -68,7 +68,14 @@ namespace ThingsGateway.Foundation.Http.WebSockets
///
///
Task ReadAsync(CancellationToken token);
-
+#if NET6_0_OR_GREATER
+ ///
+ /// 值异步等待读取数据
+ ///
+ ///
+ ///
+ public ValueTask ValueReadAsync(CancellationToken token);
+#endif
///
/// 采用WebSocket协议,发送WS数据。发送结束后,请及时释放
///
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/WebSockets/Plugins/WebSocketFeature.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/WebSockets/Plugins/WebSocketFeature.cs
index c4304ae2d..a0e8bc2d1 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/WebSockets/Plugins/WebSocketFeature.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/WebSockets/Plugins/WebSocketFeature.cs
@@ -71,7 +71,7 @@ namespace ThingsGateway.Foundation.Http.WebSockets
///
/// 验证连接
///
- public Func VerifyConnection { get; set; }
+ public Func> VerifyConnection { get; set; }
///
/// 用于WebSocket连接的路径,默认为“/ws”
@@ -98,7 +98,7 @@ namespace ThingsGateway.Foundation.Http.WebSockets
{
if (client.Protocol == Protocol.Http)
{
- if (this.VerifyConnection.Invoke(client, e.Context))
+ if (await this.VerifyConnection.Invoke(client, e.Context))
{
e.Handled = true;
_ = client.SwitchProtocolToWebSocket(e.Context);
@@ -117,7 +117,7 @@ namespace ThingsGateway.Foundation.Http.WebSockets
public async Task OnTcpDisconnected(ITcpClientBase client, DisconnectEventArgs e)
{
client.SetValue(HandshakedProperty, false);
- if (client.TryGetValue(WebSocketClientExtensions.WebSocketProperty, out var internalWebSocket))
+ if (client.TryGetValue(WebSocketClientExtension.WebSocketProperty, out var internalWebSocket))
{
_ = internalWebSocket.TryInputReceiveAsync(null);
}
@@ -145,6 +145,21 @@ namespace ThingsGateway.Foundation.Http.WebSockets
///
///
public WebSocketFeature SetVerifyConnection(Func func)
+ {
+ this.VerifyConnection = async (client, context) =>
+ {
+ await EasyTask.CompletedTask;
+ return func.Invoke(client, context);
+ };
+ return this;
+ }
+
+ ///
+ /// 验证连接
+ ///
+ ///
+ ///
+ public WebSocketFeature SetVerifyConnection(Func> func)
{
this.VerifyConnection = func;
return this;
@@ -186,7 +201,7 @@ namespace ThingsGateway.Foundation.Http.WebSockets
((HttpSocketClient)client).PongWS();
return;
}
- if (client.TryGetValue(WebSocketClientExtensions.WebSocketProperty, out var internalWebSocket))
+ if (client.TryGetValue(WebSocketClientExtension.WebSocketProperty, out var internalWebSocket))
{
if (await internalWebSocket.TryInputReceiveAsync(dataFrame))
{
@@ -196,8 +211,9 @@ namespace ThingsGateway.Foundation.Http.WebSockets
await this.m_pluginsManager.RaiseAsync(nameof(IWebSocketReceivedPlugin.OnWebSocketReceived), client, new WSDataFrameEventArgs(dataFrame));
}
- private bool ThisVerifyConnection(IHttpSocketClient client, HttpContext context)
+ private async Task ThisVerifyConnection(IHttpSocketClient client, HttpContext context)
{
+ await EasyTask.CompletedTask;
if (context.Request.Method == HttpMethod.Get)
{
if (this.WSUrl == "/" || context.Request.UrlEquals(this.WSUrl))
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Rpc/Enum/CodeGeneratorFlag.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Rpc/Enum/CodeGeneratorFlag.cs
index 00b8f8e18..6938fd58d 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Rpc/Enum/CodeGeneratorFlag.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Rpc/Enum/CodeGeneratorFlag.cs
@@ -41,12 +41,6 @@ namespace ThingsGateway.Foundation.Rpc
///
ExtensionAsync = 2,
- ///
- /// 包含扩展(源代码生成无效)
- ///
- [Obsolete("该值已被弃用,请使用颗粒度更小的配置", true)]
- IncludeExtension = 4,
-
///
/// 生成实例类同步代码(源代码生成无效)
///
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/SerialPort/EventArgs/SerialConnectingEventArgs.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/SerialPort/EventArgs/SerialConnectingEventArgs.cs
index c5e21432c..8f4e52bb8 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/SerialPort/EventArgs/SerialConnectingEventArgs.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/SerialPort/EventArgs/SerialConnectingEventArgs.cs
@@ -19,7 +19,7 @@ namespace ThingsGateway.Foundation.Serial;
///
///
///
-public delegate void SerialConnectingEventHandler(TClient client, SerialConnectingEventArgs e);
+public delegate Task SerialConnectingEventHandler(TClient client, SerialConnectingEventArgs e);
///
/// 客户端连接事件。
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/SerialPort/Interface/ISerial.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/SerialPort/Interface/ISerial.cs
index 49cc6bf5f..46c2eb575 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/SerialPort/Interface/ISerial.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/SerialPort/Interface/ISerial.cs
@@ -15,21 +15,7 @@ namespace ThingsGateway.Foundation.Serial;
///
/// 串口基接口
///
-public interface ISerial : IDisposable
+public interface ISerial : ISocket
{
- ///
- /// 发送缓存区大小。最小值=1024。
- ///
- int SendBufferSize { get; set; }
-
- ///
- /// 接收缓存区大小。最小值=1024。
- ///
- int ReceiveBufferSize { get; set; }
-
- ///
- /// 日志记录器
- ///
- ILog Logger { get; set; }
}
\ No newline at end of file
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/SerialPort/Interface/ISerialSessionBase.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/SerialPort/Interface/ISerialSessionBase.cs
index 07f435be0..9750924ef 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/SerialPort/Interface/ISerialSessionBase.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/SerialPort/Interface/ISerialSessionBase.cs
@@ -53,9 +53,9 @@ public interface ISerialSessionBase : IClient, ISender, IDefaultSender, IPluginO
///
- /// 接收模式
+ /// 判断是否在线
///
- public ReceiveType ReceiveType { get; }
+ bool Online { get; }
///
/// 串口描述
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/SerialPort/SerialPort/BaseSerial.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/SerialPort/SerialPort/BaseSerial.cs
index 31a563c72..ba85ce55c 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/SerialPort/SerialPort/BaseSerial.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/SerialPort/SerialPort/BaseSerial.cs
@@ -21,21 +21,23 @@ public abstract class BaseSerial : DependencyObject, ISerial
/// 同步根。
///
protected readonly object SyncRoot = new object();
- private int m_receiveBufferSize = 1024 * 64;
- private int m_sendBufferSize = 1024 * 64;
+ private int m_receiveBufferSize = 1024 * 10;
+ private int m_sendBufferSize = 1024 * 10;
///
public virtual int SendBufferSize
{
- get => m_sendBufferSize;
- set => m_sendBufferSize = value < 1024 ? 1024 : value;
+ get => this.m_sendBufferSize;
+ set => this.m_sendBufferSize = value < 1024 ? 1024 : value;
}
+
///
public virtual int ReceiveBufferSize
{
- get => m_receiveBufferSize;
- set => m_receiveBufferSize = value < 1024 ? 1024 : value;
+ get => this.m_receiveBufferSize;
+ set => this.m_receiveBufferSize = value < 1024 ? 1024 : value;
}
+
///
public ILog Logger { get; set; }
}
\ No newline at end of file
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/SerialPort/SerialPort/SerialCore.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/SerialPort/SerialPort/SerialCore.cs
new file mode 100644
index 000000000..c934e4833
--- /dev/null
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/SerialPort/SerialPort/SerialCore.cs
@@ -0,0 +1,396 @@
+#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.Diagnostics;
+using System.IO.Ports;
+
+namespace ThingsGateway.Foundation.Serial;
+internal sealed class InternalSerialCore : SerialCore
+{
+
+}
+///
+/// Serial核心
+///
+public class SerialCore : IDisposable, ISender
+{
+ ///
+ /// 初始缓存大小
+ ///
+ public const int BufferSize = 1024 * 10;
+ #region 字段
+
+ ///
+ /// 同步根
+ ///
+ public readonly object SyncRoot = new object();
+
+ private long m_bufferRate;
+ private bool m_disposedValue;
+ private SpinLock m_lock;
+ private bool m_online => MainSerialPort?.IsOpen == true;
+ private int m_receiveBufferSize = BufferSize;
+ private ValueCounter m_receiveCounter;
+ private int m_sendBufferSize = BufferSize;
+ private ValueCounter m_sendCounter;
+ private readonly SemaphoreSlim m_semaphore = new SemaphoreSlim(1, 1);
+ #endregion 字段
+
+ ///
+ /// Tcp核心
+ ///
+ public SerialCore()
+ {
+ this.m_lock = new SpinLock(Debugger.IsAttached);
+ this.m_receiveCounter = new ValueCounter
+ {
+ Period = TimeSpan.FromSeconds(1),
+ OnPeriod = this.OnReceivePeriod
+ };
+
+ this.m_sendCounter = new ValueCounter
+ {
+ Period = TimeSpan.FromSeconds(1),
+ OnPeriod = this.OnSendPeriod
+ };
+ }
+
+ ///
+ /// 析构函数
+ ///
+ ~SerialCore()
+ {
+ this.Dispose(disposing: false);
+ }
+
+ ///
+ public bool CanSend => this.m_online;
+
+ ///
+ /// 当中断Tcp的时候。当为时,意味着是调用。当为时,则是其他中断。
+ ///
+ public Action OnBreakOut { get; set; }
+
+ ///
+ /// 当发生异常的时候
+ ///
+ public Action OnException { get; set; }
+
+ ///
+ /// 在线状态
+ ///
+ public bool Online { get => this.m_online; }
+ ///
+ /// UserToken
+ ///
+ public ByteBlock UserToken { get; set; }
+
+ ///
+ /// 当收到数据的时候
+ ///
+ public Action OnReceived { get; set; }
+
+ ///
+ /// 接收缓存池(可以设定初始值,运行时的值会根据流速自动调整)
+ ///
+ public int ReceiveBufferSize
+ {
+ get => this.m_receiveBufferSize;
+ set
+ {
+ this.m_receiveBufferSize = value;
+ if (this.MainSerialPort != null && !MainSerialPort.IsOpen)
+ {
+ this.MainSerialPort.ReadBufferSize = value;
+ }
+ }
+ }
+
+ ///
+ /// 接收计数器
+ ///
+ public ValueCounter ReceiveCounter { get => this.m_receiveCounter; }
+
+ ///
+ /// 发送缓存池(可以设定初始值,运行时的值会根据流速自动调整)
+ ///
+ public int SendBufferSize
+ {
+ get => this.m_sendBufferSize;
+ set
+ {
+ this.m_sendBufferSize = value;
+ if (this.MainSerialPort != null && !MainSerialPort.IsOpen)
+ {
+ this.MainSerialPort.WriteBufferSize = value;
+ }
+ }
+ }
+
+ ///
+ /// 发送计数器
+ ///
+ public ValueCounter SendCounter { get => this.m_sendCounter; }
+
+ ///
+ /// SerialPort
+ ///
+ public SerialPort MainSerialPort { get; private set; }
+
+
+ ///
+ /// 开始以Iocp方式接收
+ ///
+ public virtual void BeginIocpReceive()
+ {
+ var byteBlock = BytePool.Default.GetByteBlock(this.ReceiveBufferSize);
+ this.UserToken = byteBlock;
+ byteBlock.SetLength(0);
+ if (this.MainSerialPort.BytesToRead > 0)
+ {
+ this.ProcessReceived();
+ }
+ MainSerialPort.DataReceived += MainSerialPort_DataReceived;
+ }
+
+ private void MainSerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
+ {
+ try
+ {
+ this.m_bufferRate = 1;
+ this.ProcessReceived();
+ }
+ catch (Exception ex)
+ {
+ this.PrivateBreakOut(false, ex.Message);
+ }
+ }
+
+ ///
+ /// 请求关闭
+ ///
+ ///
+ public virtual void Close(string msg)
+ {
+ this.PrivateBreakOut(true, msg);
+ }
+
+ ///
+ /// 释放对象
+ ///
+ public void Dispose()
+ {
+ this.Dispose(disposing: true);
+ GC.SuppressFinalize(this);
+ }
+
+ ///
+ /// 重置环境,并设置新的。
+ ///
+ ///
+ public virtual void Reset(SerialPort socket)
+ {
+ if (socket is null)
+ {
+ throw new ArgumentNullException(nameof(socket));
+ }
+
+ if (!socket.IsOpen)
+ {
+ throw new Exception("新的SerialPort必须在连接状态。");
+ }
+ this.Reset();
+ this.MainSerialPort = socket;
+ }
+
+ ///
+ /// 重置环境。
+ ///
+ public virtual void Reset()
+ {
+ this.m_receiveCounter.Reset();
+ this.m_sendCounter.Reset();
+ this.MainSerialPort = null;
+ this.OnReceived = null;
+ this.OnBreakOut = null;
+ this.UserToken = null;
+ this.m_bufferRate = 1;
+ this.m_lock = new SpinLock();
+ this.m_receiveBufferSize = BufferSize;
+ this.m_sendBufferSize = BufferSize;
+ }
+
+ ///
+ /// 发送数据。
+ ///
+ /// 内部会根据是否启用Ssl,进行直接发送,还是Ssl发送。
+ ///
+ ///
+ ///
+ ///
+ ///
+ public virtual void Send(byte[] buffer, int offset, int length)
+ {
+ var lockTaken = false;
+ try
+ {
+ this.m_lock.Enter(ref lockTaken);
+ this.MainSerialPort.Write(buffer, offset, length);
+ }
+ finally
+ {
+ if (lockTaken) this.m_lock.Exit(false);
+ }
+ this.m_sendCounter.Increment(length);
+ }
+
+ ///
+ /// 异步发送数据。
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public virtual async Task SendAsync(byte[] buffer, int offset, int length)
+ {
+ try
+ {
+ await this.m_semaphore.WaitAsync();
+
+ this.MainSerialPort.Write(buffer, offset, length);
+ }
+ finally
+ {
+ this.m_semaphore.Release();
+ }
+
+ this.m_sendCounter.Increment(length);
+ }
+
+ ///
+ /// 当中断Tcp时。
+ ///
+ /// 当为时,意味着是调用。当为时,则是其他中断。
+ ///
+ protected virtual void BreakOut(bool manual, string msg)
+ {
+ this.OnBreakOut?.Invoke(this, manual, msg);
+ }
+
+ ///
+ /// 释放对象
+ ///
+ ///
+ protected virtual void Dispose(bool disposing)
+ {
+ if (!this.m_disposedValue)
+ {
+ if (disposing)
+ {
+ }
+
+ this.m_disposedValue = true;
+ }
+ UserToken.SafeDispose();
+ }
+
+ ///
+ /// 当发生异常的时候
+ ///
+ ///
+ protected virtual void Exception(Exception ex)
+ {
+ this.OnException?.Invoke(this, ex);
+ }
+
+ ///
+ /// 当收到数据的时候
+ ///
+ ///
+ protected virtual void Received(ByteBlock byteBlock)
+ {
+ this.OnReceived?.Invoke(this, byteBlock);
+ }
+
+ private void HandleBuffer(ByteBlock byteBlock)
+ {
+ try
+ {
+ this.m_receiveCounter.Increment(byteBlock.Length);
+ this.Received(byteBlock);
+ }
+ catch (Exception ex)
+ {
+ this.Exception(ex);
+ }
+ finally
+ {
+ byteBlock.Dispose();
+ }
+ }
+
+ private void OnReceivePeriod(long value)
+ {
+ this.ReceiveBufferSize = TouchSocketUtility.HitBufferLength(value);
+ }
+
+ private void OnSendPeriod(long value)
+ {
+ this.SendBufferSize = TouchSocketUtility.HitBufferLength(value);
+ }
+
+ private void PrivateBreakOut(bool manual, string msg)
+ {
+ lock (this.SyncRoot)
+ {
+ if (this.m_online)
+ {
+ this.BreakOut(manual, msg);
+ }
+ }
+ }
+
+ private void ProcessReceived()
+ {
+ if (!this.m_online)
+ {
+ UserToken?.SafeDispose();
+ return;
+ }
+ if (MainSerialPort.BytesToRead > 0)
+ {
+ var byteBlock = UserToken;
+ byte[] buffer = BytePool.Default.Rent(MainSerialPort.BytesToRead);
+ int num = MainSerialPort.Read(buffer, 0, MainSerialPort.BytesToRead);
+ byteBlock.Write(buffer, 0, num);
+ byteBlock.SetLength(num);
+ this.HandleBuffer(byteBlock);
+ try
+ {
+ var newByteBlock = BytePool.Default.GetByteBlock((int)Math.Min(this.ReceiveBufferSize * this.m_bufferRate, TouchSocketUtility.MaxBufferLength));
+ newByteBlock.SetLength(0);
+ UserToken = newByteBlock;
+
+ if (MainSerialPort.BytesToRead > 0)
+ {
+ this.m_bufferRate += 2;
+ this.ProcessReceived();
+ }
+ }
+ catch (Exception ex)
+ {
+ this.PrivateBreakOut(false, ex.Message);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/SerialPort/SerialPort/SerialSession.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/SerialPort/SerialPort/SerialSession.cs
index d480a658f..11fc28c9b 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/SerialPort/SerialPort/SerialSession.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/SerialPort/SerialPort/SerialSession.cs
@@ -14,6 +14,7 @@ using System.IO.Ports;
namespace ThingsGateway.Foundation.Serial;
+
///
public class SerialSession : SerialSessionBase
{
@@ -22,15 +23,18 @@ public class SerialSession : SerialSessionBase
///
public ReceivedEventHandler Received { get; set; }
- ///
- /// 接收数据
- ///
- ///
- ///
- protected override bool HandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo)
+ ///
+ protected override async Task ReceivedData(ReceivedDataEventArgs e)
{
- this.Received?.Invoke(this, byteBlock, requestInfo);
- return false;
+ if (this.Received != null)
+ {
+ await this.Received.Invoke(this, e);
+ if (e.Handled)
+ {
+ return;
+ }
+ }
+ await base.ReceivedData(e);
}
}
@@ -46,33 +50,22 @@ public class SerialSessionBase : BaseSerial, ISerialSession
public SerialSessionBase()
{
this.Protocol = SerialPort;
- this.m_receiveCounter = new ValueCounter
- {
- Period = TimeSpan.FromSeconds(1),
- OnPeriod = this.OnReceivePeriod
- };
- this.m_sendCounter = new ValueCounter
- {
- Period = TimeSpan.FromSeconds(1),
- OnPeriod = this.OnSendPeriod
- };
+ this.m_serialCore = new InternalSerialCore();
}
-
#region 变量
private DelaySender m_delaySender;
- private long m_bufferRate = 1;
private bool m_online => MainSerialPort?.IsOpen == true;
- private ValueCounter m_receiveCounter;
- private ValueCounter m_sendCounter;
-
+ private readonly SemaphoreSlim m_semaphore = new SemaphoreSlim(1, 1);
+ private readonly InternalSerialCore m_serialCore;
#endregion 变量
#region 事件
///
public ConnectedEventHandler Connected { get; set; }
+
///
public SerialConnectingEventHandler Connecting { get; set; }
@@ -82,26 +75,28 @@ public class SerialSessionBase : BaseSerial, ISerialSession
///
public DisconnectEventHandler Disconnecting { get; set; }
- private void PrivateOnConnected(object o)
+ private Task PrivateOnConnected(object o)
{
- var e = (ConnectedEventArgs)o;
- this.OnConnected(e);
- if (e.Handled)
- {
- return;
- }
- this.PluginsManager.Raise(nameof(ITcpConnectedPlugin.OnTcpConnected), this, e);
+ return this.OnConnected((ConnectedEventArgs)o);
}
///
- /// 已经建立Tcp连接
+ /// 已经建立连接
///
///
- protected virtual void OnConnected(ConnectedEventArgs e)
+ protected virtual async Task OnConnected(ConnectedEventArgs e)
{
try
{
- this.Connected?.Invoke(this, e);
+ if (this.Connected != null)
+ {
+ await this.Connected.Invoke(this, e);
+ if (e.Handled)
+ {
+ return;
+ }
+ }
+ await this.PluginsManager.RaiseAsync(nameof(ITcpConnectedPlugin.OnTcpConnected), this, e);
}
catch (Exception ex)
{
@@ -109,30 +104,33 @@ public class SerialSessionBase : BaseSerial, ISerialSession
}
}
- private void PrivateOnConnecting(SerialConnectingEventArgs e)
+ private Task PrivateOnConnecting(SerialConnectingEventArgs e)
{
if (this.CanSetDataHandlingAdapter)
{
this.SetDataHandlingAdapter(this.Config.GetValue(TouchSocketConfigExtension.TcpDataHandlingAdapterProperty).Invoke());
}
- this.OnConnecting(e);
- if (e.Handled)
- {
- return;
- }
- this.PluginsManager.Raise(nameof(ITcpConnectingPlugin.OnTcpConnecting), this, e);
+ return this.OnConnecting(e);
}
///
- /// 准备连接的时候,此时已初始化Socket,但是并未建立Tcp连接
+ /// 准备连接的时候,此时并未建立连接
///
///
- protected virtual void OnConnecting(SerialConnectingEventArgs e)
+ protected virtual async Task OnConnecting(SerialConnectingEventArgs e)
{
try
{
- this.Connecting?.Invoke(this, e);
+ if (this.Connecting != null)
+ {
+ await this.Connecting.Invoke(this, e);
+ if (e.Handled)
+ {
+ return;
+ }
+ }
+ await this.PluginsManager.RaiseAsync(nameof(ITcpConnectingPlugin.OnTcpConnecting), this, e);
}
catch (Exception ex)
{
@@ -140,25 +138,30 @@ public class SerialSessionBase : BaseSerial, ISerialSession
}
}
- private void PrivateOnDisconnected(DisconnectEventArgs e)
+ private Task PrivateOnDisconnected(object obj)
{
- this.OnDisconnected(e);
- if (e.Handled)
- {
- return;
- }
- this.PluginsManager.Raise(nameof(ITcpDisconnectedPlugin.OnTcpDisconnected), this, e);
+ this.m_receiver?.TryInputReceive(default, default);
+ return this.OnDisconnected((DisconnectEventArgs)obj);
}
///
/// 断开连接。在客户端未设置连接状态时,不会触发
///
///
- protected virtual void OnDisconnected(DisconnectEventArgs e)
+ protected virtual async Task OnDisconnected(DisconnectEventArgs e)
{
try
{
- this.Disconnected?.Invoke(this, e);
+ if (this.Disconnected != null)
+ {
+ await this.Disconnected.Invoke(this, e).ConfigureAwait(false);
+ if (e.Handled)
+ {
+ return;
+ }
+ }
+
+ await this.PluginsManager.RaiseAsync(nameof(ITcpDisconnectedPlugin.OnTcpDisconnected), this, e).ConfigureAwait(false);
}
catch (Exception ex)
{
@@ -166,28 +169,29 @@ public class SerialSessionBase : BaseSerial, ISerialSession
}
}
- private void PrivateOnDisconnecting(DisconnectEventArgs e)
+ private Task PrivateOnDisconnecting(object obj)
{
- this.OnDisconnecting(e);
- if (e.Handled)
- {
- return;
- }
- this.PluginsManager.Raise(nameof(ITcpDisconnectingPlugin.OnTcpDisconnecting), this, e);
+ return this.OnDisconnecting((DisconnectEventArgs)obj);
}
///
/// 即将断开连接(仅主动断开时有效)。
- ///
- /// 当主动调用Close断开时。
- ///
///
///
- protected virtual void OnDisconnecting(DisconnectEventArgs e)
+ protected virtual async Task OnDisconnecting(DisconnectEventArgs e)
{
try
{
- this.Disconnecting?.Invoke(this, e);
+ if (this.Disconnecting != null)
+ {
+ await this.Disconnecting.Invoke(this, e).ConfigureAwait(false);
+ if (e.Handled)
+ {
+ return;
+ }
+ }
+
+ await this.PluginsManager.RaiseAsync(nameof(ITcpDisconnectingPlugin.OnTcpDisconnecting), this, e).ConfigureAwait(false);
}
catch (Exception ex)
{
@@ -200,16 +204,10 @@ public class SerialSessionBase : BaseSerial, ISerialSession
#region 属性
///
- public DateTime LastReceivedTime => this.m_receiveCounter.LastIncrement;
+ public DateTime LastReceivedTime => this.GetTcpCore().ReceiveCounter.LastIncrement;
///
- public DateTime LastSendTime => this.m_sendCounter.LastIncrement;
-
- ///
- public Func OnHandleRawBuffer { get; set; }
-
- ///
- public Func OnHandleReceivedData { get; set; }
+ public DateTime LastSendTime => this.GetTcpCore().SendCounter.LastIncrement;
///
public IContainer Container { get; private set; }
@@ -223,10 +221,7 @@ public class SerialSessionBase : BaseSerial, ISerialSession
///
public SingleStreamDataHandlingAdapter DataHandlingAdapter { get; private set; }
-
- ///
///
- ///
public SerialProperty SerialProperty { get; private set; }
///
public SerialPort MainSerialPort { get; private set; }
@@ -241,9 +236,6 @@ public class SerialSessionBase : BaseSerial, ISerialSession
public IPluginsManager PluginsManager { get; private set; }
- ///
- public ReceiveType ReceiveType { get; private set; }
-
///
public Protocol Protocol { get; set; }
@@ -261,32 +253,13 @@ public class SerialSessionBase : BaseSerial, ISerialSession
{
if (this.m_online)
{
- this.PrivateOnDisconnecting(new DisconnectEventArgs(true, msg));
-
+ Task.Factory.StartNew(this.PrivateOnDisconnecting, new DisconnectEventArgs(true, msg));
this.MainSerialPort.TryClose();
-
- this.MainSerialPort.SafeDispose();
- this.m_delaySender.SafeDispose();
- this.DataHandlingAdapter.SafeDispose();
- this.PrivateOnDisconnected(new DisconnectEventArgs(true, msg));
+ this.BreakOut(default, true, msg);
}
}
}
- private void BreakOut(string msg)
- {
- lock (this.SyncRoot)
- {
- if (this.m_online)
- {
-
- this.MainSerialPort.SafeDispose();
- this.m_delaySender.SafeDispose();
- this.DataHandlingAdapter.SafeDispose();
- this.PrivateOnDisconnected(new DisconnectEventArgs(false, msg));
- }
- }
- }
///
///
@@ -298,15 +271,8 @@ public class SerialSessionBase : BaseSerial, ISerialSession
{
if (this.m_online)
{
-
- this.MainSerialPort.TryClose();
- this.PrivateOnDisconnecting(new DisconnectEventArgs(true, $"{nameof(Dispose)}主动断开"));
-
- this.MainSerialPort.SafeDispose();
- this.m_delaySender.SafeDispose();
- this.DataHandlingAdapter.SafeDispose();
- this.PluginsManager.SafeDispose();
- this.PrivateOnDisconnected(new DisconnectEventArgs(true, $"{nameof(Dispose)}主动断开"));
+ Task.Factory.StartNew(this.PrivateOnDisconnecting, new DisconnectEventArgs(true, $"{nameof(Dispose)}主动断开"));
+ this.BreakOut(default, true, $"{nameof(Dispose)}主动断开");
}
}
base.Dispose(disposing);
@@ -315,6 +281,7 @@ public class SerialSessionBase : BaseSerial, ISerialSession
#endregion 断开操作
#region Connect
+
///
/// 打开串口
///
@@ -332,25 +299,32 @@ public class SerialSessionBase : BaseSerial, ISerialSession
}
if (this.Config == null)
{
- throw new ArgumentNullException("配置文件不能为空。");
+ throw new ArgumentNullException(nameof(this.Config), "配置文件不能为空。");
}
var serialProperty = this.Config.GetValue(SerialConfigExtension.SerialProperty) ?? throw new ArgumentNullException("串口配置不能为空。");
-
this.MainSerialPort.SafeDispose();
var serialPort = CreateSerial(serialProperty);
- var args = new SerialConnectingEventArgs(this.MainSerialPort);
- this.PrivateOnConnecting(args);
+ this.PrivateOnConnecting(new(serialPort))
+ .ConfigureAwait(false)
+ .GetAwaiter()
+ .GetResult();
+
serialPort.Open();
-
this.SetSerialPort(serialPort);
-
-
this.BeginReceive();
- this.PrivateOnConnected(new ConnectedEventArgs());
+
+ Task.Factory.StartNew(this.PrivateOnConnected, new ConnectedEventArgs());
}
}
+
+ private void BeginReceive()
+ {
+ this.GetTcpCore().BeginIocpReceive();
+ }
+
+
///
public virtual ISerialSession Connect()
{
@@ -366,43 +340,66 @@ public class SerialSessionBase : BaseSerial, ISerialSession
return this.Connect();
});
}
+
+ #endregion Connect
+
+ #region Receiver
+
+ private Receiver m_receiver;
+
+ ///
+ public IReceiver CreateReceiver()
+ {
+ return this.m_receiver ??= new Receiver(this);
+ }
+
+ ///
+ public void ClearReceiver()
+ {
+ this.m_receiver = null;
+ }
+
#endregion
- private void OnReceivePeriod(long value)
+ private void BreakOut(SerialCore core, bool manual, string msg)
{
- this.ReceiveBufferSize = TouchSocketUtility.HitBufferLength(value);
+ lock (this.SyncRoot)
+ {
+ if (this.m_online)
+ {
+ this.MainSerialPort.SafeDispose();
+ this.m_delaySender.SafeDispose();
+ this.DataHandlingAdapter.SafeDispose();
+ Task.Factory.StartNew(this.PrivateOnDisconnected, new DisconnectEventArgs(manual, msg));
+ }
+ }
}
- private void OnSendPeriod(long value)
+ private SerialCore GetTcpCore()
{
- this.SendBufferSize = TouchSocketUtility.HitBufferLength(value);
+ this.ThrowIfDisposed();
+ return this.m_serialCore ?? throw new ObjectDisposedException(this.GetType().Name);
}
+
+
///
public override int ReceiveBufferSize
{
- get => base.ReceiveBufferSize;
+ get => this.GetTcpCore().ReceiveBufferSize;
set
{
- base.ReceiveBufferSize = value;
- if (this.MainSerialPort != null && !MainSerialPort.IsOpen)
- {
- this.MainSerialPort.ReadBufferSize = base.ReceiveBufferSize;
- }
+ this.GetTcpCore().ReceiveBufferSize = value;
}
}
///
public override int SendBufferSize
{
- get => base.SendBufferSize;
+ get => this.GetTcpCore().SendBufferSize;
set
{
- base.SendBufferSize = value;
- if (this.MainSerialPort != null && !MainSerialPort.IsOpen)
- {
- this.MainSerialPort.WriteBufferSize = base.SendBufferSize;
- }
+ this.GetTcpCore().SendBufferSize = value;
}
}
@@ -480,32 +477,24 @@ public class SerialSessionBase : BaseSerial, ISerialSession
private void PrivateHandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo)
{
- if (this.OnHandleReceivedData?.Invoke(byteBlock, requestInfo) == false)
+ if (this.m_receiver != null)
{
- return;
- }
-
- if (this.HandleReceivedData(byteBlock, requestInfo))
- {
- return;
- }
-
- if (this.PluginsManager.Enable)
- {
- var args = new ReceivedDataEventArgs(byteBlock, requestInfo);
- this.PluginsManager.Raise(nameof(ITcpReceivedPlugin.OnTcpReceived), this, args);
+ if (this.m_receiver.TryInputReceive(byteBlock, requestInfo))
+ {
+ return;
+ }
}
+ this.ReceivedData(new ReceivedDataEventArgs(byteBlock, requestInfo)).GetFalseAwaitResult();
}
///
- /// 处理已接收到的数据。
+ /// 当收到适配器处理的数据时。
///
- /// 以二进制流形式传递
- /// 以解析的数据对象传递
+ ///
/// 如果返回则表示数据已被处理,且不会再向下传递。
- protected virtual bool HandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo)
+ protected virtual Task ReceivedData(ReceivedDataEventArgs e)
{
- return false;
+ return this.PluginsManager.RaiseAsync(nameof(ITcpReceivedPlugin.OnTcpReceived), this, e);
}
///
@@ -515,12 +504,12 @@ public class SerialSessionBase : BaseSerial, ISerialSession
/// 偏移
/// 长度
/// 返回值表示是否允许发送
- protected virtual bool HandleSendingData(byte[] buffer, int offset, int length)
+ protected virtual async Task SendingData(byte[] buffer, int offset, int length)
{
- if (this.PluginsManager.Enable)
+ if (this.PluginsManager.GetPluginCount(nameof(ITcpSendingPlugin.OnTcpSending)) > 0)
{
var args = new SendingEventArgs(buffer, offset, length);
- this.PluginsManager.Raise(nameof(ITcpSendingPlugin.OnTcpSending), this, args);
+ await this.PluginsManager.RaiseAsync(nameof(ITcpSendingPlugin.OnTcpSending), this, args).ConfigureAwait(false);
return args.IsPermitOperation;
}
return true;
@@ -534,16 +523,6 @@ public class SerialSessionBase : BaseSerial, ISerialSession
{
this.SerialProperty = config.GetValue(SerialConfigExtension.SerialProperty);
this.Logger ??= this.Container.Resolve();
- this.ReceiveType = config.GetValue(TouchSocketConfigExtension.ReceiveTypeProperty);
- }
-
- ///
- /// 在延迟发生错误
- ///
- ///
- protected virtual void OnDelaySenderError(Exception ex)
- {
- this.Logger.Log(LogLevel.Error, this, "发送错误", ex);
}
///
@@ -567,33 +546,10 @@ public class SerialSessionBase : BaseSerial, ISerialSession
adapter.OnLoaded(this);
adapter.ReceivedCallBack = this.PrivateHandleReceivedData;
adapter.SendCallBack = this.DefaultSend;
+ adapter.SendAsyncCallBack = this.DefaultSendAsync;
this.DataHandlingAdapter = adapter;
}
- private void BeginReceive()
- {
-
- if (this.ReceiveType == ReceiveType.Iocp)
- {
- SerialReceivedEventArgs eventArgs = new();
- var byteBlock = BytePool.Default.GetByteBlock(this.ReceiveBufferSize);
- byteBlock.SetLength(0);
- eventArgs.UserToken = byteBlock;
- if (this.MainSerialPort.BytesToRead > 0)
- {
- this.ProcessReceived(eventArgs);
- }
- MainSerialPort.DataReceived += this.EventArgs_Completed;
- }
- else if (this.ReceiveType == ReceiveType.Bio)
- {
- new Thread(this.BeginBio)
- {
- IsBackground = true
- }
- .Start();
- }
- }
private static SerialPort CreateSerial(SerialProperty serialProperty)
{
SerialPort serialPort = new(serialProperty.PortName, serialProperty.BaudRate, serialProperty.Parity, serialProperty.DataBits, serialProperty.StopBits)
@@ -604,88 +560,6 @@ public class SerialSessionBase : BaseSerial, ISerialSession
return serialPort;
}
- private void EventArgs_Completed(object sender, SerialDataReceivedEventArgs e)
- {
- try
- {
- this.m_bufferRate = 1;
- SerialReceivedEventArgs eventArgs = new();
- var newByteBlock = BytePool.Default.GetByteBlock((int)Math.Min(this.ReceiveBufferSize * this.m_bufferRate, TouchSocketUtility.MaxBufferLength));
- newByteBlock.SetLength(0);
- eventArgs.UserToken = newByteBlock;
- if (MainSerialPort.BytesToRead > 0)
- {
- this.ProcessReceived(eventArgs);
- }
- }
- catch (Exception ex)
- {
- this.BreakOut(ex.Message);
- }
- }
- private void BeginBio()
- {
- while (true)
- {
- var byteBlock = new ByteBlock(this.ReceiveBufferSize);
- try
- {
- int r = MainSerialPort.Read(byteBlock.Buffer, 0, MainSerialPort.BytesToRead);
- if (r == 0)
- {
- this.BreakOut("远程终端主动关闭");
- return;
- }
-
- byteBlock.SetLength(r);
- this.HandleBuffer(byteBlock);
- }
- catch (Exception ex)
- {
- this.BreakOut(ex.Message);
- return;
- }
- }
- }
-
-
- ///
- /// 处理数据
- ///
- private void HandleBuffer(ByteBlock byteBlock)
- {
- try
- {
- this.m_receiveCounter.Increment(byteBlock.Length);
- if (this.OnHandleRawBuffer?.Invoke(byteBlock) == false)
- {
- return;
- }
- if (this.DisposedValue)
- {
- return;
- }
- if (this.PluginsManager.Enable && this.PluginsManager.Raise(nameof(ITcpReceivingPlugin.OnTcpReceiving), this, new ByteBlockEventArgs(byteBlock)))
- {
- return;
- }
- if (this.DataHandlingAdapter == null)
- {
- this.Logger.Error(this, TouchSocketResource.NullDataAdapter.GetDescription());
- return;
- }
- this.DataHandlingAdapter.ReceivedInput(byteBlock);
- }
- catch (Exception ex)
- {
- this.Logger.Log(LogLevel.Error, this, "在处理数据时发生错误", ex);
- }
- finally
- {
- byteBlock.Dispose();
- }
- }
-
#region 发送
#region 同步发送
@@ -757,12 +631,14 @@ public class SerialSessionBase : BaseSerial, ISerialSession
{
length += item.Count;
}
- using var byteBlock = new ByteBlock(length);
- foreach (var item in transferBytes)
+ using (var byteBlock = new ByteBlock(length))
{
- byteBlock.Write(item.Array, item.Offset, item.Count);
+ foreach (var item in transferBytes)
+ {
+ byteBlock.Write(item.Array, item.Offset, item.Count);
+ }
+ this.DataHandlingAdapter.SendInput(byteBlock.Buffer, 0, byteBlock.Len);
}
- this.DataHandlingAdapter.SendInput(byteBlock.Buffer, 0, byteBlock.Len);
}
}
@@ -773,18 +649,20 @@ public class SerialSessionBase : BaseSerial, ISerialSession
///
///
///
- ///
- ///
- ///
- ///
- ///
- ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
public virtual Task SendAsync(byte[] buffer, int offset, int length)
{
- return Task.Run(() =>
+ this.ThrowIfDisposed();
+ if (this.DataHandlingAdapter == null)
{
- this.Send(buffer, offset, length);
- });
+ throw new ArgumentNullException(nameof(this.DataHandlingAdapter), TouchSocketResource.NullDataAdapter.GetDescription());
+ }
+ return this.DataHandlingAdapter.SendInputAsync(buffer, offset, length);
}
///
@@ -796,118 +674,78 @@ public class SerialSessionBase : BaseSerial, ISerialSession
///
public virtual Task SendAsync(IRequestInfo requestInfo)
{
- return Task.Run(() =>
+ this.ThrowIfDisposed();
+ if (this.DataHandlingAdapter == null)
{
- this.Send(requestInfo);
- });
+ throw new ArgumentNullException(nameof(this.DataHandlingAdapter), TouchSocketResource.NullDataAdapter.GetDescription());
+ }
+ if (!this.DataHandlingAdapter.CanSendRequestInfo)
+ {
+ throw new NotSupportedException($"当前适配器不支持对象发送。");
+ }
+ return this.DataHandlingAdapter.SendInputAsync(requestInfo);
}
///
///
///
- ///
- ///
- ///
- ///
+ ///
+ ///
+ ///
public virtual Task SendAsync(IList> transferBytes)
{
- return Task.Run(() =>
+ this.ThrowIfDisposed();
+ if (this.DataHandlingAdapter == null)
{
- this.Send(transferBytes);
- });
+ throw new ArgumentNullException(nameof(this.DataHandlingAdapter), TouchSocketResource.NullDataAdapter.GetDescription());
+ }
+ if (this.DataHandlingAdapter.CanSplicingSend)
+ {
+ return this.DataHandlingAdapter.SendInputAsync(transferBytes);
+ }
+ else
+ {
+ var length = 0;
+ foreach (var item in transferBytes)
+ {
+ length += item.Count;
+ }
+ using (var byteBlock = new ByteBlock(length))
+ {
+ foreach (var item in transferBytes)
+ {
+ byteBlock.Write(item.Array, item.Offset, item.Count);
+ }
+ return this.DataHandlingAdapter.SendInputAsync(byteBlock.Buffer, 0, byteBlock.Len);
+ }
+ }
}
#endregion 异步发送
- ///
///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
public void DefaultSend(byte[] buffer, int offset, int length)
{
- if (!this.m_online)
+ if (this.SendingData(buffer, offset, length).GetFalseAwaitResult())
{
- throw new NotConnectedException(TouchSocketResource.NotConnected.GetDescription());
- }
- if (this.HandleSendingData(buffer, offset, length))
- {
- if (this.m_delaySender != null && length < this.m_delaySender.DelayLength)
- {
- this.m_delaySender.Send(QueueDataBytes.CreateNew(buffer, offset, length));
- }
- else
- {
- this.MainSerialPort.AbsoluteSend(buffer, offset, length);
- }
-
- this.m_sendCounter.Increment(length);
+ this.GetTcpCore().Send(buffer, offset, length);
}
}
- ///
///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- public Task DefaultSendAsync(byte[] buffer, int offset, int length)
+ public async Task DefaultSendAsync(byte[] buffer, int offset, int length)
{
- return Task.Run(() =>
+ if (await this.SendingData(buffer, offset, length))
{
- this.DefaultSend(buffer, offset, length);
- });
+ await this.GetTcpCore().SendAsync(buffer, offset, length);
+ }
}
#endregion 发送
- private void ProcessReceived(SerialReceivedEventArgs e)
- {
- if (!this.m_online)
- {
- e.UserToken.SafeDispose();
- return;
- }
- if (MainSerialPort.BytesToRead > 0)
- {
- byte[] buffer = new byte[2048];
- var byteBlock = (ByteBlock)e.UserToken;
- int num = MainSerialPort.Read(buffer, 0, MainSerialPort.BytesToRead);
- byteBlock.Write(buffer, 0, num);
- byteBlock.SetLength(num);
- this.HandleBuffer(byteBlock);
- try
- {
- var newByteBlock = BytePool.Default.GetByteBlock((int)Math.Min(this.ReceiveBufferSize * this.m_bufferRate, TouchSocketUtility.MaxBufferLength));
- newByteBlock.SetLength(0);
- e.UserToken = newByteBlock;
+ #region 自定义
- if (MainSerialPort.BytesToRead > 0)
- {
- this.m_bufferRate += 2;
- this.ProcessReceived(e);
- }
- }
- catch (Exception ex)
- {
- e.UserToken.SafeDispose();
- this.BreakOut(ex.Message);
- }
- }
- else
- {
- e.UserToken.SafeDispose();
- this.BreakOut("远程终端主动关闭");
- }
- }
private void SetSerialPort(SerialPort serialPort)
{
@@ -917,15 +755,63 @@ public class SerialSessionBase : BaseSerial, ISerialSession
}
this.MainSerialPort = serialPort;
+ this.SerialProperty ??= new();
+ this.SerialProperty.Parity = serialPort.Parity;
+ this.SerialProperty.PortName = serialPort.PortName;
+ this.SerialProperty.StopBits = serialPort.StopBits;
+ this.SerialProperty.DataBits = serialPort.DataBits;
+ this.SerialProperty.BaudRate = serialPort.BaudRate;
+
var delaySenderOption = this.Config.GetValue(TouchSocketConfigExtension.DelaySenderProperty);
if (delaySenderOption != null)
{
this.m_delaySender = new DelaySender(delaySenderOption, this.MainSerialPort.AbsoluteSend);
}
+ this.m_serialCore.Reset(serialPort);
+ this.m_serialCore.OnReceived = this.HandleReceived;
+ this.m_serialCore.OnBreakOut = this.BreakOut;
+
}
- ///
- public override string ToString()
+
+ private void HandleReceived(SerialCore core, ByteBlock byteBlock)
{
- return SerialProperty?.ToString();
+ try
+ {
+ if (this.DisposedValue)
+ {
+ return;
+ }
+ if (this.ReceivingData(byteBlock).GetFalseAwaitResult())
+ {
+ return;
+ }
+
+ if (this.DataHandlingAdapter == null)
+ {
+ this.Logger.Error(this, TouchSocketResource.NullDataAdapter.GetDescription());
+ return;
+ }
+ this.DataHandlingAdapter.ReceivedInput(byteBlock);
+ }
+ catch (Exception ex)
+ {
+ this.Logger.Log(LogLevel.Error, this, "在处理数据时发生错误", ex);
+ }
}
+
+ ///
+ /// 当收到原始数据
+ ///
+ ///
+ /// 如果返回则表示数据已被处理,且不会再向下传递。
+ protected virtual Task ReceivingData(ByteBlock byteBlock)
+ {
+ if (this.PluginsManager.GetPluginCount(nameof(ITcpReceivingPlugin.OnTcpReceiving)) > 0)
+ {
+ return this.PluginsManager.RaiseAsync(nameof(ITcpReceivingPlugin.OnTcpReceiving), this, new ByteBlockEventArgs(byteBlock));
+ }
+ return Task.FromResult(false);
+ }
+
+ #endregion
}
\ No newline at end of file
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/BaseSocket.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/BaseSocket.cs
index 5494ab5f3..0aa687c0e 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/BaseSocket.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/BaseSocket.cs
@@ -34,21 +34,24 @@ namespace ThingsGateway.Foundation.Sockets
/// 同步根。
///
protected readonly object SyncRoot = new object();
- private int m_receiveBufferSize = 1024 * 64;
- private int m_sendBufferSize = 1024 * 64;
+
+ private int m_receiveBufferSize = 1024 * 10;
+ private int m_sendBufferSize = 1024 * 10;
///
public virtual int SendBufferSize
{
- get => m_sendBufferSize;
- set => m_sendBufferSize = value < 1024 ? 1024 : value;
+ get => this.m_sendBufferSize;
+ set => this.m_sendBufferSize = value < 1024 ? 1024 : value;
}
+
///
public virtual int ReceiveBufferSize
{
- get => m_receiveBufferSize;
- set => m_receiveBufferSize = value < 1024 ? 1024 : value;
+ get => this.m_receiveBufferSize;
+ set => this.m_receiveBufferSize = value < 1024 ? 1024 : value;
}
+
///
public ILog Logger { get; set; }
}
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Common/Options/TcpListenOption.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Common/Options/TcpListenOption.cs
index f4bb9286c..7d8f9627a 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Common/Options/TcpListenOption.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Common/Options/TcpListenOption.cs
@@ -32,11 +32,6 @@ namespace ThingsGateway.Foundation.Sockets
///
public int SendTimeout { get; set; }
- ///
- /// 接收类型
- ///
- public ReceiveType ReceiveType { get; set; } = ReceiveType.Iocp;
-
///
/// 是否使用地址复用
///
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Components/Core/TcpCore.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Components/Core/TcpCore.cs
index 54e779927..3dabb6e1b 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Components/Core/TcpCore.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Components/Core/TcpCore.cs
@@ -14,547 +14,558 @@ using System.Diagnostics;
using System.Net.Security;
using System.Net.Sockets;
-namespace ThingsGateway.Foundation.Sockets
+namespace ThingsGateway.Foundation.Sockets;
+
+///
+/// Tcp核心
+///
+public class TcpCore : SocketAsyncEventArgs, IDisposable, ISender
{
+ private const string m_msg1 = "远程终端主动关闭";
+
+ ///
+ /// 初始缓存大小
+ ///
+ public const int BufferSize = 1024 * 10;
+ #region 字段
+
+ ///
+ /// 同步根
+ ///
+ public readonly object SyncRoot = new object();
+
+ private long m_bufferRate;
+ private bool m_disposedValue;
+ private SpinLock m_lock;
+ private volatile bool m_online;
+ private int m_receiveBufferSize = BufferSize;
+ private ValueCounter m_receiveCounter;
+ private int m_sendBufferSize = BufferSize;
+ private ValueCounter m_sendCounter;
+ private readonly SemaphoreSlim m_semaphore = new SemaphoreSlim(1, 1);
+ #endregion 字段
+
///
/// Tcp核心
///
- public class TcpCore : SocketAsyncEventArgs, IDisposable, ISender
+ public TcpCore()
{
- private const string m_msg1 = "远程终端主动关闭";
-
- #region 字段
-
- ///
- /// 同步根
- ///
- public readonly object SyncRoot = new object();
-
- private long m_bufferRate;
- private bool m_disposedValue;
- private SpinLock m_lock;
- private volatile bool m_online;
- private int m_receiveBufferSize = 64 * 1024;
- private ValueCounter m_receiveCounter;
- private int m_sendBufferSize = 1024 * 64;
- private ValueCounter m_sendCounter;
- private readonly SemaphoreSlim m_semaphore = new SemaphoreSlim(1, 1);
- #endregion 字段
-
- ///
- /// Tcp核心
- ///
- public TcpCore()
+ this.m_lock = new SpinLock(Debugger.IsAttached);
+ this.m_receiveCounter = new ValueCounter
{
- this.m_lock = new SpinLock(Debugger.IsAttached);
- this.m_receiveCounter = new ValueCounter
- {
- Period = TimeSpan.FromSeconds(1),
- OnPeriod = this.OnReceivePeriod
- };
+ Period = TimeSpan.FromSeconds(1),
+ OnPeriod = this.OnReceivePeriod
+ };
- this.m_sendCounter = new ValueCounter
- {
- Period = TimeSpan.FromSeconds(1),
- OnPeriod = this.OnSendPeriod
- };
+ this.m_sendCounter = new ValueCounter
+ {
+ Period = TimeSpan.FromSeconds(1),
+ OnPeriod = this.OnSendPeriod
+ };
+ }
+
+ ///
+ /// 析构函数
+ ///
+ ~TcpCore()
+ {
+ this.Dispose(disposing: false);
+ }
+
+ ///
+ public bool CanSend => this.m_online;
+
+ ///
+ /// 当中断Tcp的时候。当为时,意味着是调用。当为时,则是其他中断。
+ ///
+ public Action OnBreakOut { get; set; }
+
+ ///
+ /// 当发生异常的时候
+ ///
+ public Action OnException { get; set; }
+
+ ///
+ /// 在线状态
+ ///
+ public bool Online { get => this.m_online; }
+
+ ///
+ /// 当收到数据的时候
+ ///
+ public Action OnReceived { get; set; }
+
+ ///
+ /// 接收缓存池(可以设定初始值,运行时的值会根据流速自动调整)
+ ///
+ public int ReceiveBufferSize
+ {
+ get => this.m_receiveBufferSize;
+ set
+ {
+ this.m_receiveBufferSize = value;
+ this.Socket.ReceiveBufferSize = value;
}
+ }
- ///
- /// 析构函数
- ///
- ~TcpCore()
+ ///
+ /// 接收计数器
+ ///
+ public ValueCounter ReceiveCounter { get => this.m_receiveCounter; }
+
+ ///
+ /// 发送缓存池(可以设定初始值,运行时的值会根据流速自动调整)
+ ///
+ public int SendBufferSize
+ {
+ get => this.m_sendBufferSize;
+ set
{
- this.Dispose(disposing: false);
+ this.m_sendBufferSize = value;
+ this.Socket.SendBufferSize = value;
}
+ }
- ///
- public bool CanSend => this.m_online;
+ ///
+ /// 发送计数器
+ ///
+ public ValueCounter SendCounter { get => this.m_sendCounter; }
- ///
- /// 当中断Tcp的时候。当为时,意味着是调用。当为时,则是其他中断。
- ///
- public Action OnBreakOut { get; set; }
+ ///
+ /// Socket
+ ///
+ public Socket Socket { get; private set; }
- ///
- /// 当发生异常的时候
- ///
- public Action OnException { get; set; }
+ ///
+ /// 提供一个用于客户端-服务器通信的流,该流使用安全套接字层 (SSL) 安全协议对服务器和(可选)客户端进行身份验证。
+ ///
+ public SslStream SslStream { get; private set; }
- ///
- /// 在线状态
- ///
- public bool Online { get => this.m_online; }
+ ///
+ /// 是否启用了Ssl
+ ///
+ public bool UseSsl { get; private set; }
- ///
- /// 当收到数据的时候
- ///
- public Action OnReceived { get; set; }
+ ///
+ /// 以Ssl服务器模式授权
+ ///
+ ///
+ public virtual void Authenticate(ServiceSslOption sslOption)
+ {
+ var sslStream = (sslOption.CertificateValidationCallback != null) ? new SslStream(new NetworkStream(this.Socket, false), false, sslOption.CertificateValidationCallback) : new SslStream(new NetworkStream(this.Socket, false), false);
+ sslStream.AuthenticateAsServer(sslOption.Certificate);
- ///
- /// 接收缓存池(可以设定初始值,运行时的值会根据流速自动调整)
- ///
- public int ReceiveBufferSize
+ this.SslStream = sslStream;
+ this.UseSsl = true;
+ }
+
+ ///
+ /// 以Ssl客户端模式授权
+ ///
+ ///
+ public virtual void Authenticate(ClientSslOption sslOption)
+ {
+ var sslStream = (sslOption.CertificateValidationCallback != null) ? new SslStream(new NetworkStream(this.Socket, false), false, sslOption.CertificateValidationCallback) : new SslStream(new NetworkStream(this.Socket, false), false);
+ if (sslOption.ClientCertificates == null)
{
- get => this.m_receiveBufferSize;
- set
- {
- this.m_receiveBufferSize = value;
- this.Socket.ReceiveBufferSize = value;
- }
+ sslStream.AuthenticateAsClient(sslOption.TargetHost);
}
-
- ///
- /// 接收计数器
- ///
- public ValueCounter ReceiveCounter { get => this.m_receiveCounter; }
-
- ///
- /// 发送缓存池(可以设定初始值,运行时的值会根据流速自动调整)
- ///
- public int SendBufferSize
+ else
{
- get => this.m_sendBufferSize;
- set
- {
- this.m_sendBufferSize = value;
- this.Socket.SendBufferSize = value;
- }
+ sslStream.AuthenticateAsClient(sslOption.TargetHost, sslOption.ClientCertificates, sslOption.SslProtocols, sslOption.CheckCertificateRevocation);
}
+ this.SslStream = sslStream;
+ this.UseSsl = true;
+ }
- ///
- /// 发送计数器
- ///
- public ValueCounter SendCounter { get => this.m_sendCounter; }
+ ///
+ /// 以Ssl服务器模式授权
+ ///
+ ///
+ ///
+ public virtual async Task AuthenticateAsync(ServiceSslOption sslOption)
+ {
+ var sslStream = (sslOption.CertificateValidationCallback != null) ? new SslStream(new NetworkStream(this.Socket, false), false, sslOption.CertificateValidationCallback) : new SslStream(new NetworkStream(this.Socket, false), false);
+ await sslStream.AuthenticateAsServerAsync(sslOption.Certificate);
- ///
- /// Socket
- ///
- public Socket Socket { get; private set; }
+ this.SslStream = sslStream;
+ this.UseSsl = true;
+ }
- ///
- /// 提供一个用于客户端-服务器通信的流,该流使用安全套接字层 (SSL) 安全协议对服务器和(可选)客户端进行身份验证。
- ///
- public SslStream SslStream { get; private set; }
-
- ///
- /// 是否启用了Ssl
- ///
- public bool UseSsl { get; private set; }
-
- ///
- /// 以Ssl服务器模式授权
- ///
- ///
- public virtual void Authenticate(ServiceSslOption sslOption)
+ ///
+ /// 以Ssl客户端模式授权
+ ///
+ ///
+ ///
+ public virtual async Task AuthenticateAsync(ClientSslOption sslOption)
+ {
+ var sslStream = (sslOption.CertificateValidationCallback != null) ? new SslStream(new NetworkStream(this.Socket, false), false, sslOption.CertificateValidationCallback) : new SslStream(new NetworkStream(this.Socket, false), false);
+ if (sslOption.ClientCertificates == null)
{
- var sslStream = (sslOption.CertificateValidationCallback != null) ? new SslStream(new NetworkStream(this.Socket, false), false, sslOption.CertificateValidationCallback) : new SslStream(new NetworkStream(this.Socket, false), false);
- sslStream.AuthenticateAsServer(sslOption.Certificate);
-
- this.SslStream = sslStream;
- this.UseSsl = true;
+ await sslStream.AuthenticateAsClientAsync(sslOption.TargetHost);
}
-
- ///
- /// 以Ssl客户端模式授权
- ///
- ///
- public virtual void Authenticate(ClientSslOption sslOption)
+ else
{
- var sslStream = (sslOption.CertificateValidationCallback != null) ? new SslStream(new NetworkStream(this.Socket, false), false, sslOption.CertificateValidationCallback) : new SslStream(new NetworkStream(this.Socket, false), false);
- if (sslOption.ClientCertificates == null)
- {
- sslStream.AuthenticateAsClient(sslOption.TargetHost);
- }
- else
- {
- sslStream.AuthenticateAsClient(sslOption.TargetHost, sslOption.ClientCertificates, sslOption.SslProtocols, sslOption.CheckCertificateRevocation);
- }
- this.SslStream = sslStream;
- this.UseSsl = true;
+ await sslStream.AuthenticateAsClientAsync(sslOption.TargetHost, sslOption.ClientCertificates, sslOption.SslProtocols, sslOption.CheckCertificateRevocation);
}
+ this.SslStream = sslStream;
+ this.UseSsl = true;
+ }
- ///
- /// 以Ssl服务器模式授权
- ///
- ///
- ///
- public virtual async Task AuthenticateAsync(ServiceSslOption sslOption)
+ ///
+ /// 开始以Iocp方式接收
+ ///
+ public virtual void BeginIocpReceive()
+ {
+ var byteBlock = BytePool.Default.GetByteBlock(this.ReceiveBufferSize);
+ this.UserToken = byteBlock;
+ this.SetBuffer(byteBlock.Buffer, 0, byteBlock.Capacity);
+ if (!this.Socket.ReceiveAsync(this))
{
- var sslStream = (sslOption.CertificateValidationCallback != null) ? new SslStream(new NetworkStream(this.Socket, false), false, sslOption.CertificateValidationCallback) : new SslStream(new NetworkStream(this.Socket, false), false);
- await sslStream.AuthenticateAsServerAsync(sslOption.Certificate);
-
- this.SslStream = sslStream;
- this.UseSsl = true;
+ this.ProcessReceived(this);
}
+ }
- ///
- /// 以Ssl客户端模式授权
- ///
- ///
- ///
- public virtual async Task AuthenticateAsync(ClientSslOption sslOption)
+ ///
+ /// 开始以Ssl接收。
+ ///
+ /// 注意,使用该方法时,应先完成授权。
+ ///
+ ///
+ ///
+ public virtual async Task BeginSslReceive()
+ {
+ if (!this.UseSsl)
{
- var sslStream = (sslOption.CertificateValidationCallback != null) ? new SslStream(new NetworkStream(this.Socket, false), false, sslOption.CertificateValidationCallback) : new SslStream(new NetworkStream(this.Socket, false), false);
- if (sslOption.ClientCertificates == null)
- {
- await sslStream.AuthenticateAsClientAsync(sslOption.TargetHost);
- }
- else
- {
- await sslStream.AuthenticateAsClientAsync(sslOption.TargetHost, sslOption.ClientCertificates, sslOption.SslProtocols, sslOption.CheckCertificateRevocation);
- }
- this.SslStream = sslStream;
- this.UseSsl = true;
+ throw new Exception("请先完成Ssl验证授权");
}
-
- ///
- /// 开始以Iocp方式接收
- ///
- public virtual void BeginIocpReceive()
- {
- var byteBlock = BytePool.Default.GetByteBlock(this.ReceiveBufferSize);
- this.UserToken = byteBlock;
- this.SetBuffer(byteBlock.Buffer, 0, byteBlock.Capacity);
- if (!this.Socket.ReceiveAsync(this))
- {
- this.ProcessReceived(this);
- }
- }
-
- ///
- /// 开始以Ssl接收。
- ///
- /// 注意,使用该方法时,应先完成授权。
- ///
- ///
- ///
- public virtual async Task BeginSslReceive()
- {
- if (!this.UseSsl)
- {
- throw new Exception("请先完成Ssl验证授权");
- }
- while (true)
- {
- var byteBlock = new ByteBlock(this.ReceiveBufferSize);
- try
- {
- var r = await Task.Factory.FromAsync(this.SslStream.BeginRead, this.SslStream.EndRead, byteBlock.Buffer, 0, byteBlock.Capacity, default);
- if (r == 0)
- {
- this.PrivateBreakOut(false, m_msg1);
- return;
- }
-
- byteBlock.SetLength(r);
- this.HandleBuffer(byteBlock);
- }
- catch (Exception ex)
- {
- byteBlock.Dispose();
- this.PrivateBreakOut(false, ex.Message);
- }
- }
- }
-
- ///
- /// 请求关闭
- ///
- ///
- public virtual void Close(string msg)
- {
- this.PrivateBreakOut(true, msg);
- }
-
- ///
- /// 释放对象
- ///
- public new void Dispose()
- {
- // 不要更改此代码。请将清理代码放入“Dispose(bool disposing)”方法中
- this.Dispose(disposing: true);
- GC.SuppressFinalize(this);
- }
-
- ///
- /// 重置环境,并设置新的。
- ///
- ///
- public virtual void Reset(Socket socket)
- {
- if (socket is null)
- {
- throw new ArgumentNullException(nameof(socket));
- }
-
- if (!socket.Connected)
- {
- throw new Exception("新的Socket必须在连接状态。");
- }
- this.Reset();
- this.m_online = true;
- this.Socket = socket;
- }
-
- ///
- /// 重置环境。
- ///
- public virtual void Reset()
- {
- this.m_receiveCounter.Reset();
- this.m_sendCounter.Reset();
- this.SslStream?.Dispose();
- this.SslStream = null;
- this.Socket = null;
- }
-
- ///
- /// 发送数据。
- ///
- /// 内部会根据是否启用Ssl,进行直接发送,还是Ssl发送。
- ///
- ///
- ///
- ///
- ///
- public virtual void Send(byte[] buffer, int offset, int length)
- {
- if (this.UseSsl)
- {
- this.SslStream.Write(buffer, offset, length);
- }
- else
- {
- var lockTaken = false;
- try
- {
- this.m_lock.Enter(ref lockTaken);
- while (length > 0)
- {
- var r = this.Socket.Send(buffer, offset, length, SocketFlags.None);
- if (r == 0 && length > 0)
- {
- throw new Exception("发送数据不完全");
- }
- offset += r;
- length -= r;
- }
- }
- finally
- {
- if (lockTaken) this.m_lock.Exit(false);
- }
- }
- this.m_sendCounter.Increment(length);
- }
-
- ///
- /// 异步发送数据。
- ///
- /// 内部会根据是否启用Ssl,进行直接发送,还是Ssl发送。
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- public virtual async Task SendAsync(byte[] buffer, int offset, int length)
- {
-#if NET6_0_OR_GREATER
- if (this.UseSsl)
- {
- await this.SslStream.WriteAsync(new ReadOnlyMemory(buffer, offset, length), CancellationToken.None);
- }
- else
- {
- try
- {
- await this.m_semaphore.WaitAsync();
-
- while (length > 0)
- {
- var r = await this.Socket.SendAsync(new ArraySegment(buffer, offset, length), SocketFlags.None, CancellationToken.None);
- if (r == 0 && length > 0)
- {
- throw new Exception("发送数据不完全");
- }
- offset += r;
- length -= r;
- }
- }
- finally
- {
- this.m_semaphore.Release();
- }
- }
-#else
- if (this.UseSsl)
- {
- await this.SslStream.WriteAsync(buffer, offset, length, CancellationToken.None);
- }
- else
- {
- try
- {
- await this.m_semaphore.WaitAsync();
-
- while (length > 0)
- {
- var r = this.Socket.Send(buffer, offset, length, SocketFlags.None);
- if (r == 0 && length > 0)
- {
- throw new Exception("发送数据不完全");
- }
- offset += r;
- length -= r;
- }
- }
- finally
- {
- this.m_semaphore.Release();
- }
- }
-#endif
-
- this.m_sendCounter.Increment(length);
- }
-
- ///
- /// 当中断Tcp时。
- ///
- /// 当为时,意味着是调用。当为时,则是其他中断。
- ///
- protected virtual void BreakOut(bool manual, string msg)
- {
- this.OnBreakOut?.Invoke(this, manual, msg);
- }
-
- ///
- /// 释放对象
- ///
- ///
- protected virtual void Dispose(bool disposing)
- {
- if (!this.m_disposedValue)
- {
- if (disposing)
- {
- }
-
- this.m_disposedValue = true;
- }
- base.Dispose();
- }
-
- ///
- /// 当发生异常的时候
- ///
- ///
- protected virtual void Exception(Exception ex)
- {
- this.OnException?.Invoke(this, ex);
- }
-
- ///
- protected override sealed void OnCompleted(SocketAsyncEventArgs e)
- {
- if (e.LastOperation == SocketAsyncOperation.Receive)
- {
- try
- {
- this.m_bufferRate = 1;
- this.ProcessReceived(e);
- }
- catch (Exception ex)
- {
- this.PrivateBreakOut(false, ex.Message);
- }
- }
- }
-
- ///
- /// 当收到数据的时候
- ///
- ///
- protected virtual void Received(ByteBlock byteBlock)
- {
- this.OnReceived?.Invoke(this, byteBlock);
- }
-
- private void HandleBuffer(ByteBlock byteBlock)
+ while (true)
{
+ var byteBlock = new ByteBlock(this.ReceiveBufferSize);
try
{
- this.m_receiveCounter.Increment(byteBlock.Length);
- this.Received(byteBlock);
+ var r = await Task.Factory.FromAsync(this.SslStream.BeginRead, this.SslStream.EndRead, byteBlock.Buffer, 0, byteBlock.Capacity, default);
+ if (r == 0)
+ {
+ this.PrivateBreakOut(false, m_msg1);
+ return;
+ }
+
+ byteBlock.SetLength(r);
+ this.HandleBuffer(byteBlock);
}
catch (Exception ex)
- {
- this.Exception(ex);
- }
- finally
{
byteBlock.Dispose();
- }
- }
-
- private void OnReceivePeriod(long value)
- {
- this.ReceiveBufferSize = TouchSocketUtility.HitBufferLength(value);
- }
-
- private void OnSendPeriod(long value)
- {
- this.SendBufferSize = TouchSocketUtility.HitBufferLength(value);
- }
-
- private void PrivateBreakOut(bool manual, string msg)
- {
- lock (this.SyncRoot)
- {
- if (this.m_online)
- {
- this.m_online = false;
- this.BreakOut(manual, msg);
- }
- }
- }
-
- private void ProcessReceived(SocketAsyncEventArgs e)
- {
- if (e.SocketError != SocketError.Success)
- {
- this.PrivateBreakOut(false, e.SocketError.ToString());
- return;
- }
- else if (e.BytesTransferred > 0)
- {
- var byteBlock = (ByteBlock)e.UserToken;
- byteBlock.SetLength(e.BytesTransferred);
- this.HandleBuffer(byteBlock);
- try
- {
- var newByteBlock = BytePool.Default.GetByteBlock((int)Math.Min(this.ReceiveBufferSize * this.m_bufferRate, TouchSocketUtility.MaxBufferLength));
- e.UserToken = newByteBlock;
- e.SetBuffer(newByteBlock.Buffer, 0, newByteBlock.Capacity);
-
- if (!this.Socket.ReceiveAsync(e))
- {
- this.m_bufferRate += 2;
- this.ProcessReceived(e);
- }
- }
- catch (Exception ex)
- {
- this.PrivateBreakOut(false, ex.Message);
- }
- }
- else
- {
- this.PrivateBreakOut(false, m_msg1);
+ this.PrivateBreakOut(false, ex.Message);
}
}
}
+
+ ///
+ /// 请求关闭
+ ///
+ ///
+ public virtual void Close(string msg)
+ {
+ this.PrivateBreakOut(true, msg);
+ }
+
+ ///
+ /// 释放对象
+ ///
+ public new void Dispose()
+ {
+ // 不要更改此代码。请将清理代码放入“Dispose(bool disposing)”方法中
+ this.Dispose(disposing: true);
+ GC.SuppressFinalize(this);
+ }
+
+ ///
+ /// 重置环境,并设置新的。
+ ///
+ ///
+ public virtual void Reset(Socket socket)
+ {
+ if (socket is null)
+ {
+ throw new ArgumentNullException(nameof(socket));
+ }
+
+ if (!socket.Connected)
+ {
+ throw new Exception("新的Socket必须在连接状态。");
+ }
+ this.Reset();
+ this.m_online = true;
+ this.Socket = socket;
+ }
+
+ ///
+ /// 重置环境。
+ ///
+ public virtual void Reset()
+ {
+ this.m_receiveCounter.Reset();
+ this.m_sendCounter.Reset();
+ this.SslStream?.Dispose();
+ this.SslStream = null;
+ this.Socket = null;
+ this.OnReceived = null;
+ this.OnBreakOut = null;
+ this.UserToken = null;
+ this.m_bufferRate = 1;
+ this.m_lock = new SpinLock();
+ this.m_receiveBufferSize = BufferSize;
+ this.m_sendBufferSize = BufferSize;
+ this.m_online = false;
+ }
+
+ ///
+ /// 发送数据。
+ ///
+ /// 内部会根据是否启用Ssl,进行直接发送,还是Ssl发送。
+ ///
+ ///
+ ///
+ ///
+ ///
+ public virtual void Send(byte[] buffer, int offset, int length)
+ {
+ if (this.UseSsl)
+ {
+ this.SslStream.Write(buffer, offset, length);
+ }
+ else
+ {
+ var lockTaken = false;
+ try
+ {
+ this.m_lock.Enter(ref lockTaken);
+ while (length > 0)
+ {
+ var r = this.Socket.Send(buffer, offset, length, SocketFlags.None);
+ if (r == 0 && length > 0)
+ {
+ throw new Exception("发送数据不完全");
+ }
+ offset += r;
+ length -= r;
+ }
+ }
+ finally
+ {
+ if (lockTaken) this.m_lock.Exit(false);
+ }
+ }
+ this.m_sendCounter.Increment(length);
+ }
+
+ ///
+ /// 异步发送数据。
+ ///
+ /// 内部会根据是否启用Ssl,进行直接发送,还是Ssl发送。
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public virtual async Task SendAsync(byte[] buffer, int offset, int length)
+ {
+#if NET6_0_OR_GREATER
+ if (this.UseSsl)
+ {
+ await this.SslStream.WriteAsync(new ReadOnlyMemory(buffer, offset, length), CancellationToken.None);
+ }
+ else
+ {
+ try
+ {
+ await this.m_semaphore.WaitAsync();
+
+ while (length > 0)
+ {
+ var r = await this.Socket.SendAsync(new ArraySegment(buffer, offset, length), SocketFlags.None, CancellationToken.None);
+ if (r == 0 && length > 0)
+ {
+ throw new Exception("发送数据不完全");
+ }
+ offset += r;
+ length -= r;
+ }
+ }
+ finally
+ {
+ this.m_semaphore.Release();
+ }
+ }
+#else
+ if (this.UseSsl)
+ {
+ await this.SslStream.WriteAsync(buffer, offset, length, CancellationToken.None);
+ }
+ else
+ {
+ try
+ {
+ await this.m_semaphore.WaitAsync();
+
+ while (length > 0)
+ {
+ var r = this.Socket.Send(buffer, offset, length, SocketFlags.None);
+ if (r == 0 && length > 0)
+ {
+ throw new Exception("发送数据不完全");
+ }
+ offset += r;
+ length -= r;
+ }
+ }
+ finally
+ {
+ this.m_semaphore.Release();
+ }
+ }
+#endif
+
+ this.m_sendCounter.Increment(length);
+ }
+
+ ///
+ /// 当中断Tcp时。
+ ///
+ /// 当为时,意味着是调用。当为时,则是其他中断。
+ ///
+ protected virtual void BreakOut(bool manual, string msg)
+ {
+ this.OnBreakOut?.Invoke(this, manual, msg);
+ }
+
+ ///
+ /// 释放对象
+ ///
+ ///
+ protected virtual void Dispose(bool disposing)
+ {
+ if (!this.m_disposedValue)
+ {
+ if (disposing)
+ {
+ }
+
+ this.m_disposedValue = true;
+ }
+ base.Dispose();
+ }
+
+ ///
+ /// 当发生异常的时候
+ ///
+ ///
+ protected virtual void Exception(Exception ex)
+ {
+ this.OnException?.Invoke(this, ex);
+ }
+
+ ///
+ protected override sealed void OnCompleted(SocketAsyncEventArgs e)
+ {
+ if (e.LastOperation == SocketAsyncOperation.Receive)
+ {
+ try
+ {
+ this.m_bufferRate = 1;
+ this.ProcessReceived(e);
+ }
+ catch (Exception ex)
+ {
+ this.PrivateBreakOut(false, ex.Message);
+ }
+ }
+ }
+
+ ///
+ /// 当收到数据的时候
+ ///
+ ///
+ protected virtual void Received(ByteBlock byteBlock)
+ {
+ this.OnReceived?.Invoke(this, byteBlock);
+ }
+
+ private void HandleBuffer(ByteBlock byteBlock)
+ {
+ try
+ {
+ this.m_receiveCounter.Increment(byteBlock.Length);
+ this.Received(byteBlock);
+ }
+ catch (Exception ex)
+ {
+ this.Exception(ex);
+ }
+ finally
+ {
+ byteBlock.Dispose();
+ }
+ }
+
+ private void OnReceivePeriod(long value)
+ {
+ this.ReceiveBufferSize = TouchSocketUtility.HitBufferLength(value);
+ }
+
+ private void OnSendPeriod(long value)
+ {
+ this.SendBufferSize = TouchSocketUtility.HitBufferLength(value);
+ }
+
+ private void PrivateBreakOut(bool manual, string msg)
+ {
+ lock (this.SyncRoot)
+ {
+ if (this.m_online)
+ {
+ this.m_online = false;
+ this.BreakOut(manual, msg);
+ }
+ }
+ }
+
+ private void ProcessReceived(SocketAsyncEventArgs e)
+ {
+ if (e.SocketError != SocketError.Success)
+ {
+ this.PrivateBreakOut(false, e.SocketError.ToString());
+ return;
+ }
+ else if (e.BytesTransferred > 0)
+ {
+ var byteBlock = (ByteBlock)e.UserToken;
+ byteBlock.SetLength(e.BytesTransferred);
+ this.HandleBuffer(byteBlock);
+ try
+ {
+ var newByteBlock = BytePool.Default.GetByteBlock((int)Math.Min(this.ReceiveBufferSize * this.m_bufferRate, TouchSocketUtility.MaxBufferLength));
+ e.UserToken = newByteBlock;
+ e.SetBuffer(newByteBlock.Buffer, 0, newByteBlock.Capacity);
+
+ if (!this.Socket.ReceiveAsync(e))
+ {
+ this.m_bufferRate += 2;
+ this.ProcessReceived(e);
+ }
+ }
+ catch (Exception ex)
+ {
+ this.PrivateBreakOut(false, ex.Message);
+ }
+ }
+ else
+ {
+ this.PrivateBreakOut(false, m_msg1);
+ }
+ }
}
\ No newline at end of file
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Components/NAT/NATService.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Components/NAT/NATService.cs
index 4fb70b0ab..dd1f4e191 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Components/NAT/NATService.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Components/NAT/NATService.cs
@@ -44,23 +44,22 @@ namespace ThingsGateway.Foundation.Sockets
/// 在NAT服务器收到数据时。
///
///
- ///
- ///
+ ///
/// 需要转发的数据。
- protected virtual byte[] OnNATReceived(NATSocketClient socketClient, ByteBlock byteBlock, IRequestInfo requestInfo)
+ protected virtual byte[] OnNATReceived(NATSocketClient socketClient, ReceivedDataEventArgs e)
{
- return byteBlock?.ToArray();
+ return e.ByteBlock?.ToArray();
}
///
///
///
///
- ///
- ///
- protected override sealed void OnReceived(NATSocketClient socketClient, ByteBlock byteBlock, IRequestInfo requestInfo)
+ ///
+ protected override sealed async Task OnReceived(NATSocketClient socketClient, ReceivedDataEventArgs e)
{
- var data = this.OnNATReceived(socketClient, byteBlock, requestInfo);
+ await EasyTask.CompletedTask;
+ var data = this.OnNATReceived(socketClient, e);
if (data != null)
{
socketClient.SendToTargetClient(data, 0, data.Length);
@@ -82,12 +81,11 @@ namespace ThingsGateway.Foundation.Sockets
///
///
///
- ///
- ///
+ ///
///
- protected virtual byte[] OnTargetClientReceived(NATSocketClient socketClient, ITcpClient tcpClient, ByteBlock byteBlock, IRequestInfo requestInfo)
+ protected virtual byte[] OnTargetClientReceived(NATSocketClient socketClient, ITcpClient tcpClient, ReceivedDataEventArgs e)
{
- return byteBlock?.ToArray();
+ return e.ByteBlock?.ToArray();
}
}
}
\ No newline at end of file
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Components/NAT/NATSocketClient.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Components/NAT/NATSocketClient.cs
index be559590f..68093c623 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Components/NAT/NATSocketClient.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Components/NAT/NATSocketClient.cs
@@ -31,7 +31,7 @@ namespace ThingsGateway.Foundation.Sockets
public class NATSocketClient : SocketClient
{
internal Action m_internalDis;
- internal Func m_internalTargetClientRev;
+ internal Func m_internalTargetClientRev;
private readonly ConcurrentList m_targetClients = new ConcurrentList();
///
@@ -100,18 +100,19 @@ namespace ThingsGateway.Foundation.Sockets
///
///
///
- protected override void OnDisconnected(DisconnectEventArgs e)
+ protected override async Task OnDisconnected(DisconnectEventArgs e)
{
foreach (var client in this.m_targetClients)
{
client.TryShutdown();
client.SafeDispose();
}
- base.OnDisconnected(e);
+ await base.OnDisconnected(e);
}
- private void TcpClient_Disconnected(ITcpClientBase client, DisconnectEventArgs e)
+ private async Task TcpClient_Disconnected(ITcpClientBase client, DisconnectEventArgs e)
{
+ await EasyTask.CompletedTask;
foreach (var item in client.PluginsManager.Plugins)
{
if (typeof(ReconnectionPlugin<>) == item.GetType().GetGenericTypeDefinition())
@@ -125,8 +126,9 @@ namespace ThingsGateway.Foundation.Sockets
this.m_internalDis?.Invoke(this, (ITcpClient)client, e);
}
- private void TcpClient_Received(TcpClient client, ByteBlock byteBlock, IRequestInfo requestInfo)
+ private async Task TcpClient_Received(TcpClient client, ReceivedDataEventArgs e)
{
+ await EasyTask.CompletedTask;
if (this.DisposedValue)
{
return;
@@ -134,7 +136,7 @@ namespace ThingsGateway.Foundation.Sockets
try
{
- var data = this.m_internalTargetClientRev?.Invoke(this, client, byteBlock, requestInfo);
+ var data = this.m_internalTargetClientRev?.Invoke(this, client, e);
if (data != null)
{
if (this.CanSend)
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Components/Tcp/SocketClient.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Components/Tcp/SocketClient.cs
index 250a2bfa4..aa37a1e25 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Components/Tcp/SocketClient.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Components/Tcp/SocketClient.cs
@@ -23,7 +23,6 @@
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using System.Diagnostics;
-using System.Net.Security;
using System.Net.Sockets;
namespace ThingsGateway.Foundation.Sockets
@@ -40,24 +39,26 @@ namespace ThingsGateway.Foundation.Sockets
public SocketClient()
{
this.Protocol = Protocol.Tcp;
- this.m_receiveCounter = new ValueCounter
- {
- Period = TimeSpan.FromSeconds(1),
- OnPeriod = this.OnReceivePeriod
- };
- m_sendCounter = new ValueCounter
- {
- Period = TimeSpan.FromSeconds(1),
- OnPeriod = this.OnSendPeriod
- };
+ //this.m_receiveCounter = new ValueCounter
+ //{
+ // Period = TimeSpan.FromSeconds(1),
+ // OnPeriod = this.OnReceivePeriod
+ //};
+ //m_sendCounter = new ValueCounter
+ //{
+ // Period = TimeSpan.FromSeconds(1),
+ // OnPeriod = this.OnSendPeriod
+ //};
}
#region 变量
- private ValueCounter m_receiveCounter;
- private ValueCounter m_sendCounter;
- private long m_bufferRate = 1;
+
+ //private ValueCounter m_receiveCounter;
+ //private ValueCounter m_sendCounter;
+ //private long m_bufferRate = 1;
private DelaySender m_delaySender;
- private Stream m_workStream;
+
+ private TcpCore m_tcpCore;
#endregion 变量
@@ -87,6 +88,15 @@ namespace ThingsGateway.Foundation.Sockets
///
public bool IsClient => false;
+ ///
+ public DateTime LastReceivedTime => this.GetTcpCore().ReceiveCounter.LastIncrement;
+
+ ///
+ public DateTime LastSendTime => this.GetTcpCore().SendCounter.LastIncrement;
+
+ ///
+ public TcpListenOption ListenOption { get; private set; }
+
///
public Socket MainSocket { get; private set; }
@@ -102,36 +112,18 @@ namespace ThingsGateway.Foundation.Sockets
///
public Protocol Protocol { get; set; }
- ///
- public TcpListenOption ListenOption { get; private set; }
-
- ///
- public ReceiveType ReceiveType { get; private set; }
-
///
public TcpServiceBase Service { get; private set; }
- ///
- public bool UseSsl { get; private set; }
-
- ///
- public DateTime LastReceivedTime => this.m_receiveCounter.LastIncrement;
-
- ///
- public DateTime LastSendTime => this.m_sendCounter.LastIncrement;
-
- ///
- public Func OnHandleRawBuffer { get; set; }
-
- ///
- public Func OnHandleReceivedData { get; set; }
-
///
public string ServiceIP { get; private set; }
///
public int ServicePort { get; private set; }
+ ///
+ public bool UseSsl { get; private set; }
+
#endregion 属性
#region Internal
@@ -140,71 +132,50 @@ namespace ThingsGateway.Foundation.Sockets
{
try
{
- if (this.ReceiveType == ReceiveType.Iocp)
- {
- var eventArgs = new SocketAsyncEventArgs();
- eventArgs.Completed += this.EventArgs_Completed;
- var byteBlock = BytePool.Default.GetByteBlock(this.ReceiveBufferSize);
- eventArgs.UserToken = byteBlock;
- eventArgs.SetBuffer(byteBlock.Buffer, 0, byteBlock.Capacity);
- if (!this.MainSocket.ReceiveAsync(eventArgs))
- {
- this.ProcessReceived(eventArgs);
- }
- }
+ this.m_tcpCore.BeginIocpReceive();
+ //if (this.ReceiveType == ReceiveType.Iocp)
+ //{
+ // //var eventArgs = new SocketAsyncEventArgs();
+ // //eventArgs.Completed += this.EventArgs_Completed;
+ // //var byteBlock = BytePool.Default.GetByteBlock(this.ReceiveBufferSize);
+ // //eventArgs.UserToken = byteBlock;
+ // //eventArgs.SetBuffer(byteBlock.Buffer, 0, byteBlock.Capacity);
+ // //if (!this.MainSocket.ReceiveAsync(eventArgs))
+ // //{
+ // // this.ProcessReceived(eventArgs);
+ // //}
+
+ //}
}
catch (Exception ex)
{
- this.BreakOut(ex.Message, false);
+ this.BreakOut(default, false, ex.Message);
}
}
- internal void BeginReceiveSsl(ServiceSslOption sslOption)
+ internal Task AuthenticateAsync(ServiceSslOption sslOption)
{
- var sslStream = (sslOption.CertificateValidationCallback != null) ? new SslStream(new NetworkStream(this.MainSocket, false), false, sslOption.CertificateValidationCallback) : new SslStream(new NetworkStream(this.MainSocket, false), false);
- sslStream.AuthenticateAsServer(sslOption.Certificate);
- this.m_workStream = sslStream;
- this.UseSsl = true;
- if (this.ReceiveType == ReceiveType.Iocp)
- {
- this.BeginSsl();
- }
+ return this.m_tcpCore.AuthenticateAsync(sslOption);
+ }
+ internal Task BeginReceiveSsl()
+ {
+ return this.m_tcpCore.BeginSslReceive();
}
- internal void InternalConnected(ConnectedEventArgs e)
+ internal Task InternalConnected(ConnectedEventArgs e)
{
this.Online = true;
-
- this.OnConnected(e);
-
- if (e.Handled)
- {
- return;
- }
-
-
- if (this.PluginsManager.Enable && this.PluginsManager.Raise(nameof(ITcpConnectedPlugin.OnTcpConnected), this, e))
- {
- return;
- }
+ return this.OnConnected(e);
}
- internal void InternalConnecting(ConnectingEventArgs e)
+ internal Task InternalConnecting(ConnectingEventArgs e)
{
- this.OnConnecting(e);
- if (e.Handled)
- {
- return;
- }
- if (this.PluginsManager.Enable && this.PluginsManager.Raise(nameof(ITcpConnectingPlugin.OnTcpConnecting), this, e))
- {
- return;
- }
+ return this.OnConnecting(e);
}
- internal void InternalInitialized()
+ internal Task InternalInitialized()
{
- this.OnInitialized();
+ return this.OnInitialized();
}
internal void InternalSetConfig(TouchSocketConfig config)
@@ -223,15 +194,15 @@ namespace ThingsGateway.Foundation.Sockets
this.Id = id;
}
- internal void InternalSetPluginsManager(IPluginsManager pluginsManager)
- {
- this.PluginsManager = pluginsManager;
- }
-
internal void InternalSetListenOption(TcpListenOption option)
{
this.ListenOption = option;
- this.ReceiveType = option.ReceiveType;
+ //this.ReceiveType = option.ReceiveType;
+ }
+
+ internal void InternalSetPluginsManager(IPluginsManager pluginsManager)
+ {
+ this.PluginsManager = pluginsManager;
}
internal void InternalSetService(TcpServiceBase serviceBase)
@@ -239,18 +210,68 @@ namespace ThingsGateway.Foundation.Sockets
this.Service = serviceBase;
}
- internal void InternalSetSocket(Socket mainSocket)
+ internal void InternalSetSocket(Socket socket)
{
- this.MainSocket = mainSocket ?? throw new ArgumentNullException(nameof(mainSocket));
- this.IP = mainSocket.RemoteEndPoint.GetIP();
- this.Port = mainSocket.RemoteEndPoint.GetPort();
- this.ServiceIP = mainSocket.LocalEndPoint.GetIP();
- this.ServicePort = mainSocket.LocalEndPoint.GetPort();
+ this.MainSocket = socket ?? throw new ArgumentNullException(nameof(socket));
+ this.IP = socket.RemoteEndPoint.GetIP();
+ this.Port = socket.RemoteEndPoint.GetPort();
+ this.ServiceIP = socket.LocalEndPoint.GetIP();
+ this.ServicePort = socket.LocalEndPoint.GetPort();
if (this.Config.GetValue(TouchSocketConfigExtension.DelaySenderProperty) is DelaySenderOption senderOption)
{
this.m_delaySender = new DelaySender(senderOption, this.MainSocket.AbsoluteSend);
}
+
+ var tcpCore = this.Service.RentTcpCore();
+ tcpCore.Reset(socket);
+ tcpCore.OnReceived = this.HandleReceived;
+ tcpCore.OnBreakOut = this.BreakOut;
+ this.m_tcpCore = tcpCore;
+ }
+
+ private void BreakOut(TcpCore core, bool manual, string msg)
+ {
+ if (this.GetSocketCliectCollection().TryRemove(this.Id, out _))
+ {
+ if (this.Online)
+ {
+ this.Online = false;
+ this.MainSocket.SafeDispose();
+ this.m_delaySender.SafeDispose();
+ this.DataHandlingAdapter.SafeDispose();
+ Task.Factory.StartNew(this.PrivateOnDisconnected, new DisconnectEventArgs(manual, msg));
+ }
+ }
+
+ base.Dispose(true);
+ }
+
+ private void HandleReceived(TcpCore core, ByteBlock byteBlock)
+ {
+ try
+ {
+ if (this.DisposedValue)
+ {
+ return;
+ }
+
+ if (this.ReceivingData(byteBlock).ConfigureAwait(false).GetAwaiter().GetResult())
+ {
+ return;
+ }
+
+ if (this.DataHandlingAdapter == null)
+ {
+ this.Logger.Error(this, TouchSocketResource.NullDataAdapter.GetDescription());
+ return;
+ }
+ this.DataHandlingAdapter.ReceivedInput(byteBlock);
+ }
+ catch (Exception ex)
+ {
+ this.Logger.Log(LogLevel.Error, this, "在处理数据时发生错误", ex);
+ }
}
#endregion Internal
@@ -264,43 +285,74 @@ namespace ThingsGateway.Foundation.Sockets
public DisconnectEventHandler Disconnecting { get; set; }
///
- /// 当客户端完整建立TCP连接。
+ /// 当客户端完整建立Tcp连接。
///
///
- protected virtual void OnConnected(ConnectedEventArgs e)
+ protected virtual async Task OnConnected(ConnectedEventArgs e)
{
- this.Service.OnInternalConnected(this, e);
+ if (await this.PluginsManager.RaiseAsync(nameof(ITcpConnectedPlugin.OnTcpConnected), this, e))
+ {
+ return;
+ }
+ await this.Service.OnInternalConnected(this, e);
}
///
/// 客户端正在连接。
///
- protected virtual void OnConnecting(ConnectingEventArgs e)
+ protected virtual async Task OnConnecting(ConnectingEventArgs e)
{
- this.Service.OnInternalConnecting(this, e);
+ if (await this.PluginsManager.RaiseAsync(nameof(ITcpConnectingPlugin.OnTcpConnecting), this, e))
+ {
+ return;
+ }
+ await this.Service.OnInternalConnecting(this, e);
}
///
/// 客户端已断开连接。
///
///
- protected virtual void OnDisconnected(DisconnectEventArgs e)
+ protected virtual async Task OnDisconnected(DisconnectEventArgs e)
{
- this.Disconnected?.Invoke(this, e);
+ if (this.Disconnected != null)
+ {
+ await this.Disconnected.Invoke(this, e);
+ if (e.Handled)
+ {
+ return;
+ }
+ }
+
+ if (await this.PluginsManager.RaiseAsync(nameof(ITcpDisconnectedPlugin.OnTcpDisconnected), this, e))
+ {
+ return;
+ }
+ await this.Service.OnInternalDisconnected(this, e);
}
///
/// 即将断开连接(仅主动断开时有效)。
- ///
- /// 当主动调用Close断开时。
- ///
///
///
- protected virtual void OnDisconnecting(DisconnectEventArgs e)
+ protected virtual async Task OnDisconnecting(DisconnectEventArgs e)
{
try
{
- this.Disconnecting?.Invoke(this, e);
+ if (this.Disconnecting != null)
+ {
+ await this.Disconnecting.Invoke(this, e);
+ if (e.Handled)
+ {
+ return;
+ }
+ }
+
+ if (await this.PluginsManager.RaiseAsync(nameof(ITcpDisconnectingPlugin.OnTcpDisconnecting), this, e))
+ {
+ return;
+ }
+ await this.Service.OnInternalDisconnecting(this, e);
}
catch (Exception ex)
{
@@ -311,42 +363,33 @@ namespace ThingsGateway.Foundation.Sockets
///
/// 当初始化完成时,执行在之前。
///
- protected virtual void OnInitialized()
+ protected virtual Task OnInitialized()
{
+ return EasyTask.CompletedTask;
}
- private void PrivateOnDisconnected(DisconnectEventArgs e)
+ private Task PrivateOnDisconnecting(object obj)
{
- this.OnDisconnected(e);
- if (e.Handled)
- {
- return;
- }
-
- if (this.PluginsManager.Enable && this.PluginsManager.Raise(nameof(ITcpDisconnectedPlugin.OnTcpDisconnected), this, e))
- {
- return;
- }
-
- if (!e.Handled)
- {
- this.Service.OnInternalDisconnected(this, e);
- }
+ return this.OnDisconnecting((DisconnectEventArgs)obj);
}
- private void PrivateOnDisconnecting(DisconnectEventArgs e)
+ private async Task PrivateOnDisconnected(object obj)
{
- this.OnDisconnecting(e);
- if (e.Handled)
+ this.m_receiver?.TryInputReceive(default, default);
+ var e = (DisconnectEventArgs)obj;
+ try
{
- return;
+ await this.OnDisconnected(e);
}
-
- if (this.PluginsManager.Enable && this.PluginsManager.Raise(nameof(ITcpDisconnectingPlugin.OnTcpDisconnecting), this, e))
+ catch (Exception)
{
- return;
}
- this.Service.OnInternalDisconnecting(this, e);
+ finally
+ {
+ var tcp = this.m_tcpCore;
+ this.m_tcpCore = null;
+ this.Service?.ReturnTcpCore(tcp);
+ }
}
#endregion 事件&委托
@@ -354,62 +397,37 @@ namespace ThingsGateway.Foundation.Sockets
///
public override int ReceiveBufferSize
{
- get => base.ReceiveBufferSize;
+ get => this.GetTcpCore().ReceiveBufferSize;
set
{
- base.ReceiveBufferSize = value;
- if (this.MainSocket != null)
- {
- this.MainSocket.ReceiveBufferSize = base.ReceiveBufferSize;
- }
+ this.GetTcpCore().ReceiveBufferSize = value;
}
}
///
public override int SendBufferSize
{
- get => base.SendBufferSize;
+ get => this.GetTcpCore().SendBufferSize;
set
{
- base.SendBufferSize = value;
- if (this.MainSocket != null)
- {
- this.MainSocket.SendBufferSize = base.SendBufferSize;
- }
+ this.GetTcpCore().SendBufferSize = value;
}
}
- private void OnSendPeriod(long value)
- {
- this.SendBufferSize = TouchSocketUtility.HitBufferLength(value);
- }
- private void OnReceivePeriod(long value)
- {
- this.ReceiveBufferSize = TouchSocketUtility.HitBufferLength(value);
- }
-
///
public virtual void Close(string msg = TouchSocketCoreUtility.Empty)
{
-
lock (this.SyncRoot)
{
if (this.Online)
{
+ Task.Factory.StartNew(this.PrivateOnDisconnecting, new DisconnectEventArgs(true, msg));
this.MainSocket.TryClose();
- this.PrivateOnDisconnecting(new DisconnectEventArgs(true, msg));
+ this.BreakOut(default, true, msg);
}
- this.BreakOut(msg, true);
}
}
- ///
- public Stream GetStream()
- {
- this.m_workStream ??= new NetworkStream(this.MainSocket, true);
- return this.m_workStream;
- }
-
///
///
///
@@ -440,6 +458,7 @@ namespace ThingsGateway.Foundation.Sockets
///
protected void DirectResetId(string newId)
{
+ this.ThrowIfDisposed();
if (string.IsNullOrEmpty(newId))
{
throw new ArgumentException($"“{nameof(newId)}”不能为 null 或空。", nameof(newId));
@@ -455,11 +474,7 @@ namespace ThingsGateway.Foundation.Sockets
socketClient.Id = newId;
if (this.GetSocketCliectCollection().TryAdd(socketClient))
{
- if (this.PluginsManager.Enable)
- {
- var e = new IdChangedEventArgs(oldId, newId);
- this.PluginsManager.Raise(nameof(IIdChangedPlugin.OnIdChanged), socketClient, e);
- }
+ this.IdChanged(oldId, newId).ConfigureAwait(false).GetAwaiter().GetResult();
return;
}
else
@@ -488,43 +503,73 @@ namespace ThingsGateway.Foundation.Sockets
{
if (this.Online)
{
- this.PrivateOnDisconnecting(new DisconnectEventArgs(true, $"{nameof(Dispose)}主动断开"));
+ Task.Factory.StartNew(this.PrivateOnDisconnecting, new DisconnectEventArgs(true, $"{nameof(Dispose)}主动断开"));
+ this.BreakOut(default, true, $"{nameof(Dispose)}主动断开");
}
- this.BreakOut($"{nameof(Dispose)}主动断开", true);
+
base.Dispose(disposing);
}
}
///
- /// 处理已接收到的数据。
- /// 根据不同的数据处理适配器,会传递不同的数据
- ///
- /// 以二进制流形式传递
- /// 以解析的数据对象传递
- /// 如果返回则表示数据已被处理,且不会再向下传递。
- protected virtual bool HandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo)
- {
- return false;
- }
-
- ///
- /// 当即将发送时。
+ /// 当即将发送时,如果覆盖父类方法,则不会触发插件。
///
/// 数据缓存区
/// 偏移
/// 长度
/// 返回值表示是否允许发送
- protected virtual bool HandleSendingData(byte[] buffer, int offset, int length)
+ protected virtual async Task SendingData(byte[] buffer, int offset, int length)
{
- if (this.PluginsManager.Enable)
+ if (this.PluginsManager.GetPluginCount(nameof(ITcpSendingPlugin.OnTcpSending)) > 0)
{
var args = new SendingEventArgs(buffer, offset, length);
- this.PluginsManager.Raise(nameof(ITcpSendingPlugin.OnTcpSending), this, args);
+ await this.PluginsManager.RaiseAsync(nameof(ITcpSendingPlugin.OnTcpSending), this, args).ConfigureAwait(false);
return args.IsPermitOperation;
}
return true;
}
+ ///
+ /// 当Id更新的时候触发
+ ///
+ ///
+ ///
+ ///
+ protected Task IdChanged(string oldId, string newId)
+ {
+ return this.PluginsManager.RaiseAsync(nameof(IIdChangedPlugin.OnIdChanged), this, new IdChangedEventArgs(oldId, newId));
+ }
+
+ ///
+ /// 当收到适配器处理的数据时。
+ ///
+ /// 如果返回则表示数据已被处理,且不会再向下传递。
+ protected virtual async Task ReceivedData(ReceivedDataEventArgs e)
+ {
+ await this.PluginsManager.RaiseAsync(nameof(ITcpReceivedPlugin.OnTcpReceived), this, e);
+
+ if (e.Handled)
+ {
+ return;
+ }
+
+ await this.Service.OnInternalReceivedData(this, e);
+ }
+
+ ///
+ /// 当收到原始数据
+ ///
+ ///
+ /// 如果返回则表示数据已被处理,且不会再向下传递。
+ protected virtual Task ReceivingData(ByteBlock byteBlock)
+ {
+ if (this.PluginsManager.GetPluginCount(nameof(ITcpReceivingPlugin.OnTcpReceiving)) > 0)
+ {
+ return this.PluginsManager.RaiseAsync(nameof(ITcpReceivingPlugin.OnTcpReceiving), this, new ByteBlockEventArgs(byteBlock));
+ }
+ return Task.FromResult(false);
+ }
+
///
/// 设置适配器,该方法不会检验的值。
///
@@ -545,237 +590,51 @@ namespace ThingsGateway.Foundation.Sockets
adapter.OnLoaded(this);
adapter.ReceivedCallBack = this.PrivateHandleReceivedData;
adapter.SendCallBack = this.DefaultSend;
+ adapter.SendAsyncCallBack = this.DefaultSendAsync;
this.DataHandlingAdapter = adapter;
}
- private void BeginSsl()
- {
- if (!this.DisposedValue)
- {
- var byteBlock = new ByteBlock(this.ReceiveBufferSize);
- try
- {
- this.m_workStream.BeginRead(byteBlock.Buffer, 0, byteBlock.Capacity, this.EndSsl, byteBlock);
- }
- catch (Exception ex)
- {
- byteBlock.SafeDispose();
- this.BreakOut(ex.Message, false);
- }
- }
- }
-
- private void BreakOut(string msg, bool manual)
- {
- lock (this.SyncRoot)
- {
- if (this.GetSocketCliectCollection().TryRemove(this.Id, out _))
- {
- if (this.Online)
- {
- this.Online = false;
- this.MainSocket.SafeDispose();
- this.m_delaySender.SafeDispose();
- this.DataHandlingAdapter.SafeDispose();
- this.PrivateOnDisconnected(new DisconnectEventArgs(manual, msg));
- }
- }
-
- base.Dispose(true);
- }
- }
-
- private void EndSsl(IAsyncResult result)
- {
- var byteBlock = (ByteBlock)result.AsyncState;
- try
- {
- var r = this.m_workStream.EndRead(result);
- if (r == 0)
- {
- this.BreakOut("远程终端主动关闭", false);
- return;
- }
- byteBlock.SetLength(r);
-
- this.HandleBuffer(byteBlock);
- this.BeginSsl();
- }
- catch (Exception ex)
- {
- byteBlock.SafeDispose();
- this.BreakOut(ex.Message, false);
- }
- }
-
- private void EventArgs_Completed(object sender, SocketAsyncEventArgs e)
- {
- try
- {
- this.m_bufferRate = 1;
- this.ProcessReceived(e);
- }
- catch (Exception ex)
- {
- e.SafeDispose();
- this.BreakOut(ex.Message, false);
- }
- }
-
private SocketClientCollection GetSocketCliectCollection()
{
- return this.Service?.SocketClients as SocketClientCollection;
+ return this.Service.SocketClients as SocketClientCollection;
}
- private void HandleBuffer(ByteBlock byteBlock)
+ private TcpCore GetTcpCore()
{
- try
- {
- if (this.DisposedValue)
- {
- return;
- }
- this.m_receiveCounter.Increment(byteBlock.Length);
- if (this.OnHandleRawBuffer?.Invoke(byteBlock) == false)
- {
- return;
- }
- if (this.PluginsManager.Enable && this.PluginsManager.Raise(nameof(ITcpReceivingPlugin.OnTcpReceiving), this, new ByteBlockEventArgs(byteBlock)))
- {
- return;
- }
- if (this.DataHandlingAdapter == null)
- {
- this.Logger.Error(this, TouchSocketResource.NullDataAdapter.GetDescription());
- return;
- }
- this.DataHandlingAdapter.ReceivedInput(byteBlock);
- }
- catch (Exception ex)
- {
- this.Logger.Log(LogLevel.Error, this, "在处理数据时发生错误", ex);
- }
- finally
- {
- byteBlock.Dispose();
- }
+ this.ThrowIfDisposed();
+ return this.m_tcpCore ?? throw new ObjectDisposedException(this.GetType().Name);
}
private void PrivateHandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo)
{
- if (this.OnHandleReceivedData?.Invoke(byteBlock, requestInfo) == false)
+ if (this.m_receiver != null)
{
- return;
- }
-
- if (this.HandleReceivedData(byteBlock, requestInfo))
- {
- return;
- }
-
- if (this.PluginsManager.GetPluginCount(nameof(ITcpReceivedPlugin.OnTcpReceived)) > 0 && this.PluginsManager.Raise(nameof(ITcpReceivedPlugin.OnTcpReceived), this, new ReceivedDataEventArgs(byteBlock, requestInfo)))
- {
- return;
- }
-
- this.Service.OnInternalReceivedData(this, byteBlock, requestInfo);
- }
-
- private void ProcessReceived(SocketAsyncEventArgs e)
- {
- if (this.DisposedValue)
- {
- e.SafeDispose();
- return;
- }
-
- if (e.SocketError != SocketError.Success)
- {
- e.SafeDispose();
- this.BreakOut(e.SocketError.ToString(), false);
- }
- else if (e.BytesTransferred > 0)
- {
- var byteBlock = (ByteBlock)e.UserToken;
- byteBlock.SetLength(e.BytesTransferred);
- this.HandleBuffer(byteBlock);
- try
+ if (this.m_receiver.TryInputReceive(byteBlock, requestInfo))
{
- var newByteBlock = new ByteBlock((int)Math.Min(this.ReceiveBufferSize * this.m_bufferRate, TouchSocketUtility.MaxBufferLength));
- e.UserToken = newByteBlock;
- e.SetBuffer(newByteBlock.Buffer, 0, newByteBlock.Capacity);
-
- if (!this.MainSocket.ReceiveAsync(e))
- {
- this.m_bufferRate += 2;
- this.ProcessReceived(e);
- }
- }
- catch (Exception ex)
- {
- this.BreakOut(ex.Message, false);
+ return;
}
}
- else
- {
- e.SafeDispose();
- this.BreakOut("远程主机主动断开连接", false);
- }
+ this.ReceivedData(new ReceivedDataEventArgs(byteBlock, requestInfo)).GetFalseAwaitResult();
}
#region 发送
- ///
///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
public void DefaultSend(byte[] buffer, int offset, int length)
{
- if (!this.CanSend)
+ if (this.SendingData(buffer, offset, length).GetFalseAwaitResult())
{
- throw new NotConnectedException(TouchSocketResource.NotConnected.GetDescription());
- }
- if (this.HandleSendingData(buffer, offset, length))
- {
- if (this.UseSsl)
- {
- this.m_workStream.Write(buffer, offset, length);
- }
- else
- {
- if (this.m_delaySender != null && length < this.m_delaySender.DelayLength)
- {
- this.m_delaySender.Send(QueueDataBytes.CreateNew(buffer, offset, length));
- }
- else
- {
- this.MainSocket.AbsoluteSend(buffer, offset, length);
- }
- }
- this.m_sendCounter.Increment(length);
+ this.GetTcpCore().Send(buffer, offset, length);
}
}
- ///
///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- public Task DefaultSendAsync(byte[] buffer, int offset, int length)
+ public async Task DefaultSendAsync(byte[] buffer, int offset, int length)
{
- return Task.Run(() =>
+ if (await this.SendingData(buffer, offset, length))
{
- this.DefaultSend(buffer, offset, length);
- });
+ await this.GetTcpCore().SendAsync(buffer, offset, length);
+ }
}
#region 同步发送
@@ -789,10 +648,7 @@ namespace ThingsGateway.Foundation.Sockets
///
public virtual void Send(IRequestInfo requestInfo)
{
- if (this.DisposedValue)
- {
- return;
- }
+ this.ThrowIfDisposed();
if (this.DataHandlingAdapter == null)
{
throw new ArgumentNullException(nameof(this.DataHandlingAdapter), TouchSocketResource.NullDataAdapter.GetDescription());
@@ -815,10 +671,7 @@ namespace ThingsGateway.Foundation.Sockets
///
public virtual void Send(byte[] buffer, int offset, int length)
{
- if (this.DisposedValue)
- {
- return;
- }
+ this.ThrowIfDisposed();
if (this.DataHandlingAdapter == null)
{
throw new ArgumentNullException(nameof(this.DataHandlingAdapter), TouchSocketResource.NullDataAdapter.GetDescription());
@@ -832,10 +685,7 @@ namespace ThingsGateway.Foundation.Sockets
///
public virtual void Send(IList> transferBytes)
{
- if (this.DisposedValue)
- {
- return;
- }
+ this.ThrowIfDisposed();
if (this.DataHandlingAdapter == null)
{
throw new ArgumentNullException(nameof(this.DataHandlingAdapter), TouchSocketResource.NullDataAdapter.GetDescription());
@@ -867,7 +717,7 @@ namespace ThingsGateway.Foundation.Sockets
#region 异步发送
///
- /// IOCP发送
+ ///
///
///
///
@@ -877,10 +727,12 @@ namespace ThingsGateway.Foundation.Sockets
///
public virtual Task SendAsync(byte[] buffer, int offset, int length)
{
- return Task.Run(() =>
+ this.ThrowIfDisposed();
+ if (this.DataHandlingAdapter == null)
{
- this.Send(buffer, offset, length);
- });
+ throw new ArgumentNullException(nameof(this.DataHandlingAdapter), TouchSocketResource.NullDataAdapter.GetDescription());
+ }
+ return this.DataHandlingAdapter.SendInputAsync(buffer, offset, length);
}
///
@@ -892,22 +744,51 @@ namespace ThingsGateway.Foundation.Sockets
///
public virtual Task SendAsync(IRequestInfo requestInfo)
{
- return Task.Run(() =>
+ this.ThrowIfDisposed();
+ if (this.DataHandlingAdapter == null)
{
- this.Send(requestInfo);
- });
+ throw new ArgumentNullException(nameof(this.DataHandlingAdapter), TouchSocketResource.NullDataAdapter.GetDescription());
+ }
+ if (!this.DataHandlingAdapter.CanSendRequestInfo)
+ {
+ throw new NotSupportedException($"当前适配器不支持对象发送。");
+ }
+ return this.DataHandlingAdapter.SendInputAsync(requestInfo);
}
///
///
///
///
+ ///
+ ///
public virtual Task SendAsync(IList> transferBytes)
{
- return Task.Run(() =>
+ this.ThrowIfDisposed();
+ if (this.DataHandlingAdapter == null)
{
- this.Send(transferBytes);
- });
+ throw new ArgumentNullException(nameof(this.DataHandlingAdapter), TouchSocketResource.NullDataAdapter.GetDescription());
+ }
+ if (this.DataHandlingAdapter.CanSplicingSend)
+ {
+ return this.DataHandlingAdapter.SendInputAsync(transferBytes);
+ }
+ else
+ {
+ var length = 0;
+ foreach (var item in transferBytes)
+ {
+ length += item.Count;
+ }
+ using (var byteBlock = new ByteBlock(length))
+ {
+ foreach (var item in transferBytes)
+ {
+ byteBlock.Write(item.Array, item.Offset, item.Count);
+ }
+ return this.DataHandlingAdapter.SendInputAsync(byteBlock.Buffer, 0, byteBlock.Len);
+ }
+ }
}
#endregion 异步发送
@@ -970,13 +851,22 @@ namespace ThingsGateway.Foundation.Sockets
#endregion 发送
- ///
+ #region Receiver
+
+ private Receiver m_receiver;
+
///
- ///
- ///
- public override string ToString()
+ public IReceiver CreateReceiver()
{
- return this.GetIPPort();
+ return this.m_receiver ??= new Receiver(this);
}
+
+ ///
+ public void ClearReceiver()
+ {
+ this.m_receiver = null;
+ }
+
+ #endregion
}
}
\ No newline at end of file
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Components/Tcp/TcpClient.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Components/Tcp/TcpClient.cs
index c46a3bbc9..3477347f1 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Components/Tcp/TcpClient.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Components/Tcp/TcpClient.cs
@@ -22,1186 +22,969 @@
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
-using System.Net.Security;
using System.Net.Sockets;
using System.Runtime.InteropServices;
-namespace ThingsGateway.Foundation.Sockets;
-
-///
-/// 简单TCP客户端
-///
-public class TcpClient : TcpClientBase
-{
-
- ///
- /// 接收到数据
- ///
- public ReceivedEventHandler Received { get; set; }
-
- ///
- /// 接收数据
- ///
- ///
- ///
- protected override bool HandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo)
- {
- this.Received?.Invoke(this, byteBlock, requestInfo);
- return false;
- }
-}
-
-///
-/// TCP客户端
-///
-[System.Diagnostics.DebuggerDisplay("{IP}:{Port}")]
-public class TcpClientBase : BaseSocket, ITcpClient
+namespace ThingsGateway.Foundation.Sockets
{
///
- /// 构造函数
+ /// 简单Tcp客户端
///
- public TcpClientBase()
+ public class TcpClient : TcpClientBase
{
- this.Protocol = Protocol.Tcp;
- this.m_receiveCounter = new ValueCounter
+ ///
+ /// 接收到数据
+ ///
+ public ReceivedEventHandler Received { get; set; }
+
+ ///
+ protected override async Task ReceivedData(ReceivedDataEventArgs e)
{
- Period = TimeSpan.FromSeconds(1),
- OnPeriod = this.OnReceivePeriod
- };
- this.m_sendCounter = new ValueCounter
- {
- Period = TimeSpan.FromSeconds(1),
- OnPeriod = this.OnSendPeriod
- };
- this.m_tcpCore = new InternalTcpCore()
- {
- OnReceived = this.HandleBuffer
- };
- }
-
- #region 变量
-
- private DelaySender m_delaySender;
- private Stream m_workStream;
- private long m_bufferRate = 1;
- private volatile bool m_online;
- private ValueCounter m_receiveCounter;
- private ValueCounter m_sendCounter;
- private InternalTcpCore m_tcpCore;
-
- #endregion 变量
-
- #region 事件
-
- ///
- public ConnectedEventHandler Connected { get; set; }
-
- ///
- public ConnectingEventHandler Connecting { get; set; }
-
- ///
- public DisconnectEventHandler Disconnected { get; set; }
-
- ///
- public DisconnectEventHandler Disconnecting { get; set; }
-
- private void PrivateOnConnected(object o)
- {
- var e = (ConnectedEventArgs)o;
- this.OnConnected(e);
- if (e.Handled)
- {
- return;
- }
- this.PluginsManager.Raise(nameof(ITcpConnectedPlugin.OnTcpConnected), this, e);
- }
-
- ///
- /// 已经建立Tcp连接
- ///
- ///
- protected virtual void OnConnected(ConnectedEventArgs e)
- {
- try
- {
- this.Connected?.Invoke(this, e);
- }
- catch (Exception ex)
- {
- this.Logger.Log(LogLevel.Error, this, $"在事件{nameof(this.Connected)}中发生错误。", ex);
- }
- }
-
- private void PrivateOnConnecting(ConnectingEventArgs e)
- {
- if (this.CanSetDataHandlingAdapter)
- {
- this.SetDataHandlingAdapter(this.Config.GetValue(TouchSocketConfigExtension.TcpDataHandlingAdapterProperty).Invoke());
- }
-
- this.OnConnecting(e);
- if (e.Handled)
- {
- return;
- }
- this.PluginsManager.Raise(nameof(ITcpConnectingPlugin.OnTcpConnecting), this, e);
- }
-
- ///
- /// 准备连接的时候,此时已初始化Socket,但是并未建立Tcp连接
- ///
- ///
- protected virtual void OnConnecting(ConnectingEventArgs e)
- {
- try
- {
- this.Connecting?.Invoke(this, e);
- }
- catch (Exception ex)
- {
- this.Logger.Log(LogLevel.Error, this, $"在事件{nameof(this.OnConnecting)}中发生错误。", ex);
- }
- }
-
- private void PrivateOnDisconnected(DisconnectEventArgs e)
- {
- this.OnDisconnected(e);
- if (e.Handled)
- {
- return;
- }
- this.PluginsManager.Raise(nameof(ITcpDisconnectedPlugin.OnTcpDisconnected), this, e);
- }
-
- ///
- /// 断开连接。在客户端未设置连接状态时,不会触发
- ///
- ///
- protected virtual void OnDisconnected(DisconnectEventArgs e)
- {
- try
- {
- this.Disconnected?.Invoke(this, e);
- }
- catch (Exception ex)
- {
- this.Logger.Log(LogLevel.Error, this, $"在事件{nameof(this.Disconnected)}中发生错误。", ex);
- }
- }
-
- private void PrivateOnDisconnecting(DisconnectEventArgs e)
- {
- this.OnDisconnecting(e);
- if (e.Handled)
- {
- return;
- }
- this.PluginsManager.Raise(nameof(ITcpDisconnectingPlugin.OnTcpDisconnecting), this, e);
- }
-
- ///
- /// 即将断开连接(仅主动断开时有效)。
- ///
- /// 当主动调用Close断开时。
- ///
- ///
- ///
- protected virtual void OnDisconnecting(DisconnectEventArgs e)
- {
- try
- {
- this.Disconnecting?.Invoke(this, e);
- }
- catch (Exception ex)
- {
- this.Logger.Log(LogLevel.Error, this, $"在事件{nameof(this.Disconnecting)}中发生错误。", ex);
- }
- }
-
- #endregion 事件
-
- #region 属性
-
- ///
- public DateTime LastReceivedTime => this.m_receiveCounter.LastIncrement;
-
- ///
- public DateTime LastSendTime => this.m_sendCounter.LastIncrement;
-
- ///
- public Func OnHandleRawBuffer { get; set; }
-
- ///
- public Func OnHandleReceivedData { get; set; }
-
- ///
- public IContainer Container { get; private set; }
-
- ///
- public virtual bool CanSetDataHandlingAdapter => true;
-
- ///
- public TouchSocketConfig Config { get; private set; }
-
- ///
- public SingleStreamDataHandlingAdapter DataHandlingAdapter { get; private set; }
-
- ///
- public string IP { get; private set; }
-
- ///
- public Socket MainSocket { get; private set; }
-
- ///
- public bool Online { get => this.m_online; }
-
- ///
- public bool CanSend => this.m_online;
-
- ///
- public IPluginsManager PluginsManager { get; private set; }
-
- ///
- public int Port { get; private set; }
-
- ///
- public ReceiveType ReceiveType { get; private set; }
-
- ///
- public bool UseSsl { get; private set; }
-
- ///
- public Protocol Protocol { get; set; }
-
- ///
- public IPHost RemoteIPHost { get; private set; }
-
- ///
- public bool IsClient => true;
-
- #endregion 属性
- private EasyLock EasyLock { get; set; } = new();
-
- #region 断开操作
-
- ///
- public virtual void Close(string msg = TouchSocketCoreUtility.Empty)
- {
- lock (this.SyncRoot)
- {
- if (this.m_online)
+ if (this.Received != null)
{
- this.PrivateOnDisconnecting(new DisconnectEventArgs(true, msg));
-
- this.m_online = false;
- this.MainSocket.TryClose();
-
- this.MainSocket.SafeDispose();
- this.m_delaySender.SafeDispose();
- this.m_workStream.SafeDispose();
- this.DataHandlingAdapter.SafeDispose();
- this.PrivateOnDisconnected(new DisconnectEventArgs(true, msg));
- }
- }
- }
-
- private void BreakOut(string msg)
- {
- lock (this.SyncRoot)
- {
- if (this.m_online)
- {
- this.m_online = false;
- this.MainSocket.SafeDispose();
- this.m_delaySender.SafeDispose();
- this.m_workStream.SafeDispose();
- this.DataHandlingAdapter.SafeDispose();
- this.PrivateOnDisconnected(new DisconnectEventArgs(false, msg));
- }
- }
- }
-
- ///
- ///
- ///
- ///
- protected override void Dispose(bool disposing)
- {
- lock (this.SyncRoot)
- {
- if (this.m_online)
- {
- this.m_online = false;
- this.MainSocket.TryClose();
- this.PrivateOnDisconnecting(new DisconnectEventArgs(true, $"{nameof(Dispose)}主动断开"));
-
- this.MainSocket.SafeDispose();
- this.m_delaySender.SafeDispose();
- this.m_workStream.SafeDispose();
- this.DataHandlingAdapter.SafeDispose();
- this.PluginsManager.SafeDispose();
- this.PrivateOnDisconnected(new DisconnectEventArgs(true, $"{nameof(Dispose)}主动断开"));
- }
- }
- base.Dispose(disposing);
- }
-
- #endregion 断开操作
-
- #region Connect
-
- ///
- /// 建立Tcp的连接。
- ///
- ///
- ///
- ///
- ///
- ///
- protected void TcpConnect(int timeout)
- {
- lock (this.SyncRoot)
- {
- if (this.m_online)
- {
- return;
- }
- if (this.DisposedValue)
- {
- throw new ObjectDisposedException(this.GetType().FullName);
- }
- if (this.Config == null)
- {
- throw new ArgumentNullException(nameof(this.Config), "配置文件不能为空。");
- }
- var iPHost = this.Config.GetValue(TouchSocketConfigExtension.RemoteIPHostProperty) ?? throw new ArgumentNullException(nameof(IPHost), "iPHost不能为空。");
- this.MainSocket.SafeDispose();
- var socket = this.CreateSocket(iPHost);
- this.PrivateOnConnecting(new ConnectingEventArgs(socket));
- if (timeout == 5000)
- {
- socket.Connect(iPHost.Host, iPHost.Port);
- }
- else
- {
- var task = Task.Run(() =>
+ await this.Received.Invoke(this, e);
+ if (e.Handled)
{
- socket.Connect(iPHost.Host, iPHost.Port);
- });
- task.ConfigureAwait(false);
- if (!task.Wait(timeout))
- {
- socket.SafeDispose();
- throw new TimeoutException();
- }
- }
- this.m_online = true;
- this.SetSocket(socket);
- this.BeginReceive();
- this.PrivateOnConnected(new ConnectedEventArgs());
- }
- }
-
- ///
- /// 异步连接服务器
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- protected virtual async Task TcpConnectAsync(int timeout, CancellationToken cancellationToken = default)
- {
- try
- {
- await EasyLock.WaitAsync();
- if (m_online)
- {
- return;
- }
- if (DisposedValue)
- {
- throw new ObjectDisposedException(GetType().FullName);
- }
- if (Config == null)
- {
- throw new ArgumentNullException("配置文件不能为空。");
- }
- var iPHost = Config.GetValue(TouchSocketConfigExtension.RemoteIPHostProperty) ?? throw new ArgumentNullException("iPHost不能为空。");
- MainSocket.SafeDispose();
- var socket = CreateSocket(iPHost);
- var args = new ConnectingEventArgs(socket);
- PrivateOnConnecting(args);
-
-#if (NET6_0_OR_GREATER)
- using CancellationTokenSource cancellationTokenSource = new(timeout);
- using CancellationTokenSource stoppingToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationTokenSource.Token, cancellationToken);
- try
- {
- await socket.ConnectAsync(iPHost.EndPoint, stoppingToken.Token);
- }
- catch (OperationCanceledException)
- {
- throw new TimeoutException("连接超时");
- }
- success(socket);
-
-#else
- using CancellationTokenSource cancellationTokenSource = new();
- using CancellationTokenSource stoppingToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationTokenSource.Token, cancellationToken);
- var task = Task.Factory.FromAsync(socket.BeginConnect(iPHost.EndPoint, null, null), socket.EndConnect);
- var result = await Task.WhenAny(task, Task.Delay(timeout, stoppingToken.Token));
- if (result == task)
- {
- cancellationTokenSource.Cancel();
- if (task.Exception != null)
- {
- socket?.SafeDispose();
- throw task.Exception;
- }
- else
- {
- success(socket);
- }
- }
- else
- {
- socket?.SafeDispose();
- throw new TimeoutException("连接超时");
- }
-#endif
-
- }
- finally
- {
- EasyLock.Release();
- }
-
- void success(Socket socket)
- {
- m_online = true;
- SetSocket(socket);
- BeginReceive();
- PrivateOnConnected(new ConnectedEventArgs());
- }
- }
-
- ///
- public virtual ITcpClient Connect(int timeout = 5000)
- {
- TcpConnect(timeout);
- return this;
- }
-
- ///
- public virtual async Task ConnectAsync(int timeout = 5000)
- {
- await TcpConnectAsync(timeout);
- return this;
- }
- ///
- public virtual async Task ConnectAsync(int timeout, CancellationToken cancellationToken)
- {
- await TcpConnectAsync(timeout, cancellationToken);
- return this;
- }
- #endregion
-
- ///
- public Stream GetStream()
- {
- this.ThrowIfDisposed();
- this.m_workStream ??= new NetworkStream(this.MainSocket, true);
- return this.m_workStream;
- }
-
- private void OnReceivePeriod(long value)
- {
- this.ReceiveBufferSize = TouchSocketUtility.HitBufferLength(value);
- }
-
- private void OnSendPeriod(long value)
- {
- this.SendBufferSize = TouchSocketUtility.HitBufferLength(value);
- }
-
- ///
- public override int ReceiveBufferSize
- {
- get => base.ReceiveBufferSize;
- set
- {
- base.ReceiveBufferSize = value;
- if (this.MainSocket != null)
- {
- this.MainSocket.ReceiveBufferSize = base.ReceiveBufferSize;
- }
- }
- }
-
- ///
- public override int SendBufferSize
- {
- get => base.SendBufferSize;
- set
- {
- base.SendBufferSize = value;
- if (this.MainSocket != null)
- {
- this.MainSocket.SendBufferSize = base.SendBufferSize;
- }
- }
- }
-
- ///
- public virtual void SetDataHandlingAdapter(SingleStreamDataHandlingAdapter adapter)
- {
- if (!this.CanSetDataHandlingAdapter)
- {
- throw new Exception($"不允许自由调用{nameof(SetDataHandlingAdapter)}进行赋值。");
- }
-
- this.SetAdapter(adapter);
- }
-
- ///
- public ITcpClient Setup(string ipHost)
- {
- var config = new TouchSocketConfig();
- config.SetRemoteIPHost(new IPHost(ipHost));
- return this.Setup(config);
- }
-
- ///
- 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();
- }
-
- if (!(config.GetValue(TouchSocketCoreConfigExtension.PluginsManagerProperty) is IPluginsManager pluginsManager))
- {
- pluginsManager = new PluginsManager(container);
- }
-
- if (container.IsRegistered(typeof(IPluginsManager)))
- {
- pluginsManager = container.Resolve();
- }
- else
- {
- container.RegisterSingleton(pluginsManager);
- }
-
- if (config.GetValue(TouchSocketCoreConfigExtension.ConfigureContainerProperty) is Action actionContainer)
- {
- actionContainer.Invoke(container);
- }
-
- if (config.GetValue(TouchSocketCoreConfigExtension.ConfigurePluginsProperty) is Action actionPluginsManager)
- {
- pluginsManager.Enable = true;
- actionPluginsManager.Invoke(pluginsManager);
- }
- this.Container = container;
- this.PluginsManager = pluginsManager;
- }
-
- private void PrivateHandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo)
- {
- if (this.OnHandleReceivedData?.Invoke(byteBlock, requestInfo) == false)
- {
- return;
- }
-
- if (this.HandleReceivedData(byteBlock, requestInfo))
- {
- return;
- }
-
- if (this.PluginsManager.Enable)
- {
- var args = new ReceivedDataEventArgs(byteBlock, requestInfo);
- this.PluginsManager.Raise(nameof(ITcpReceivedPlugin.OnTcpReceived), this, args);
- }
- }
-
- ///
- /// 处理已接收到的数据。
- ///
- /// 以二进制流形式传递
- /// 以解析的数据对象传递
- /// 如果返回则表示数据已被处理,且不会再向下传递。
- protected virtual bool HandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo)
- {
- return false;
- }
-
- ///
- /// 当即将发送时,如果覆盖父类方法,则不会触发插件。
- ///
- /// 数据缓存区
- /// 偏移
- /// 长度
- /// 返回值表示是否允许发送
- protected virtual bool HandleSendingData(byte[] buffer, int offset, int length)
- {
- if (this.PluginsManager.Enable)
- {
- var args = new SendingEventArgs(buffer, offset, length);
- this.PluginsManager.Raise(nameof(ITcpSendingPlugin.OnTcpSending), this, args);
- return args.IsPermitOperation;
- }
- return true;
- }
-
- ///
- /// 加载配置
- ///
- ///
- protected virtual void LoadConfig(TouchSocketConfig config)
- {
- this.RemoteIPHost = config.GetValue(TouchSocketConfigExtension.RemoteIPHostProperty);
- this.Logger ??= this.Container.Resolve();
- this.ReceiveType = config.GetValue(TouchSocketConfigExtension.ReceiveTypeProperty);
- }
-
- ///
- /// 设置适配器,该方法不会检验的值。
- ///
- ///
- protected void SetAdapter(SingleStreamDataHandlingAdapter adapter)
- {
- this.ThrowIfDisposed();
- if (adapter is null)
- {
- throw new ArgumentNullException(nameof(adapter));
- }
-
- if (this.Config != null)
- {
- adapter.Config(this.Config);
- }
-
- adapter.Logger = this.Logger;
- adapter.OnLoaded(this);
- adapter.ReceivedCallBack = this.PrivateHandleReceivedData;
- adapter.SendCallBack = this.DefaultSend;
- this.DataHandlingAdapter = adapter;
- }
-
- private void BeginReceive()
- {
- if (this.Config.GetValue(TouchSocketConfigExtension.SslOptionProperty) != null)
- {
- this.UseSsl = true;
- }
- if (this.UseSsl)
- {
- var sslOption = (ClientSslOption)this.Config.GetValue(TouchSocketConfigExtension.SslOptionProperty);
- var sslStream = (sslOption.CertificateValidationCallback != null) ? new SslStream(new NetworkStream(this.MainSocket, false), false, sslOption.CertificateValidationCallback) : new SslStream(new NetworkStream(this.MainSocket, false), false);
- if (sslOption.ClientCertificates == null)
- {
- sslStream.AuthenticateAsClient(sslOption.TargetHost);
- }
- else
- {
- sslStream.AuthenticateAsClient(sslOption.TargetHost, sslOption.ClientCertificates, sslOption.SslProtocols, sslOption.CheckCertificateRevocation);
- }
- this.m_workStream = sslStream;
- if (this.ReceiveType != ReceiveType.None)
- {
- this.BeginSsl();
- }
- }
- else
- {
- if (this.ReceiveType == ReceiveType.Iocp)
- {
- var eventArgs = new SocketAsyncEventArgs();
- eventArgs.Completed += this.EventArgs_Completed;
-
- var byteBlock = BytePool.Default.GetByteBlock(this.ReceiveBufferSize);
- eventArgs.UserToken = byteBlock;
- eventArgs.SetBuffer(byteBlock.Buffer, 0, byteBlock.Capacity);
- if (!this.MainSocket.ReceiveAsync(eventArgs))
- {
- this.ProcessReceived(eventArgs);
- }
- }
- else if (this.ReceiveType == ReceiveType.Bio)
- {
- new Thread(this.BeginBio)
- {
- IsBackground = true
- }
- .Start();
- }
- }
- }
-
- private void BeginBio()
- {
- while (true)
- {
- var byteBlock = new ByteBlock(this.ReceiveBufferSize);
- try
- {
- var r = this.MainSocket.Receive(byteBlock.Buffer);
- if (r == 0)
- {
- this.BreakOut("远程终端主动关闭");
return;
}
+ }
+ await base.ReceivedData(e);
+ }
+ }
- byteBlock.SetLength(r);
- this.HandleBuffer(byteBlock);
+ ///
+ /// Tcp客户端
+ ///
+ [System.Diagnostics.DebuggerDisplay("{IP}:{Port}")]
+ public class TcpClientBase : BaseSocket, ITcpClient
+ {
+ ///
+ /// 构造函数
+ ///
+ public TcpClientBase()
+ {
+ this.Protocol = Protocol.Tcp;
+ this.m_tcpCore = new InternalTcpCore();
+ }
+
+ #region 变量
+
+ private DelaySender m_delaySender;
+ private volatile bool m_online;
+ private readonly SemaphoreSlim m_semaphore = new SemaphoreSlim(1, 1);
+ private readonly InternalTcpCore m_tcpCore;
+ #endregion 变量
+
+ #region 事件
+
+ ///
+ public ConnectedEventHandler Connected { get; set; }
+
+ ///
+ public ConnectingEventHandler Connecting { get; set; }
+
+ ///
+ public DisconnectEventHandler Disconnected { get; set; }
+
+ ///
+ public DisconnectEventHandler Disconnecting { get; set; }
+
+ private Task PrivateOnConnected(object o)
+ {
+ return this.OnConnected((ConnectedEventArgs)o);
+ }
+
+ ///
+ /// 已经建立Tcp连接
+ ///
+ ///
+ protected virtual async Task OnConnected(ConnectedEventArgs e)
+ {
+ try
+ {
+ if (this.Connected != null)
+ {
+ await this.Connected.Invoke(this, e);
+ if (e.Handled)
+ {
+ return;
+ }
+ }
+ await this.PluginsManager.RaiseAsync(nameof(ITcpConnectedPlugin.OnTcpConnected), this, e);
}
catch (Exception ex)
{
- this.BreakOut(ex.Message);
- return;
+ this.Logger.Log(LogLevel.Error, this, $"在事件{nameof(this.Connected)}中发生错误。", ex);
}
}
- }
- private void BeginSsl()
- {
- var byteBlock = new ByteBlock(this.ReceiveBufferSize);
- try
+ private Task PrivateOnConnecting(ConnectingEventArgs e)
{
- this.m_workStream.BeginRead(byteBlock.Buffer, 0, byteBlock.Capacity, this.EndSsl, byteBlock);
- }
- catch (Exception ex)
- {
- byteBlock.Dispose();
- this.BreakOut(ex.Message);
- }
- }
-
- private void EndSsl(IAsyncResult result)
- {
- var byteBlock = (ByteBlock)result.AsyncState;
- try
- {
- var r = this.m_workStream.EndRead(result);
- if (r == 0)
+ if (this.CanSetDataHandlingAdapter)
{
- this.BreakOut("远程终端主动关闭");
+ this.SetDataHandlingAdapter(this.Config.GetValue(TouchSocketConfigExtension.TcpDataHandlingAdapterProperty).Invoke());
}
- byteBlock.SetLength(r);
- this.HandleBuffer(byteBlock);
- this.BeginSsl();
- }
- catch (Exception ex)
- {
- byteBlock.Dispose();
- this.BreakOut(ex.Message);
- }
- }
- private Socket CreateSocket(IPHost iPHost)
- {
- Socket socket;
- if (iPHost.HostNameType == UriHostNameType.Dns)
- {
- socket = new Socket(SocketType.Stream, ProtocolType.Tcp)
- {
- SendTimeout = this.Config.GetValue(TouchSocketConfigExtension.SendTimeoutProperty)
- };
+ return this.OnConnecting(e);
}
- else
+
+ ///
+ /// 准备连接的时候,此时已初始化Socket,但是并未建立Tcp连接
+ ///
+ ///
+ protected virtual async Task OnConnecting(ConnectingEventArgs e)
{
- socket = new Socket(iPHost.EndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp)
+ try
{
- SendTimeout = this.Config.GetValue(TouchSocketConfigExtension.SendTimeoutProperty)
- };
+ if (this.Connecting != null)
+ {
+ await this.Connecting.Invoke(this, e);
+ if (e.Handled)
+ {
+ return;
+ }
+ }
+ await this.PluginsManager.RaiseAsync(nameof(ITcpConnectingPlugin.OnTcpConnecting), this, e);
+ }
+ catch (Exception ex)
+ {
+ this.Logger.Log(LogLevel.Error, this, $"在事件{nameof(this.OnConnecting)}中发生错误。", ex);
+ }
}
- if (this.Config.GetValue(TouchSocketConfigExtension.KeepAliveValueProperty) is KeepAliveValue keepAliveValue)
+
+ private Task PrivateOnDisconnected(object obj)
{
+ this.m_receiver?.TryInputReceive(default, default);
+ return this.OnDisconnected((DisconnectEventArgs)obj);
+ }
+
+ ///
+ /// 断开连接。在客户端未设置连接状态时,不会触发
+ ///
+ ///
+ protected virtual async Task OnDisconnected(DisconnectEventArgs e)
+ {
+ try
+ {
+ if (this.Disconnected != null)
+ {
+ await this.Disconnected.Invoke(this, e).ConfigureAwait(false);
+ if (e.Handled)
+ {
+ return;
+ }
+ }
+
+ await this.PluginsManager.RaiseAsync(nameof(ITcpDisconnectedPlugin.OnTcpDisconnected), this, e).ConfigureAwait(false);
+ }
+ catch (Exception ex)
+ {
+ this.Logger.Log(LogLevel.Error, this, $"在事件{nameof(this.Disconnected)}中发生错误。", ex);
+ }
+ }
+
+ private Task PrivateOnDisconnecting(object obj)
+ {
+ return this.OnDisconnecting((DisconnectEventArgs)obj);
+ }
+
+ ///
+ /// 即将断开连接(仅主动断开时有效)。
+ ///
+ ///
+ protected virtual async Task OnDisconnecting(DisconnectEventArgs e)
+ {
+ try
+ {
+ if (this.Disconnecting != null)
+ {
+ await this.Disconnecting.Invoke(this, e).ConfigureAwait(false);
+ if (e.Handled)
+ {
+ return;
+ }
+ }
+
+ await this.PluginsManager.RaiseAsync(nameof(ITcpDisconnectingPlugin.OnTcpDisconnecting), this, e).ConfigureAwait(false);
+ }
+ catch (Exception ex)
+ {
+ this.Logger.Log(LogLevel.Error, this, $"在事件{nameof(this.Disconnecting)}中发生错误。", ex);
+ }
+ }
+
+ #endregion 事件
+
+ #region 属性
+
+ ///
+ public DateTime LastReceivedTime => this.GetTcpCore().ReceiveCounter.LastIncrement;
+
+ ///
+ public DateTime LastSendTime => this.GetTcpCore().SendCounter.LastIncrement;
+
+ ///
+ public IContainer Container { get; private set; }
+
+ ///
+ public virtual bool CanSetDataHandlingAdapter => true;
+
+ ///
+ public TouchSocketConfig Config { get; private set; }
+
+ ///
+ public SingleStreamDataHandlingAdapter DataHandlingAdapter { get; private set; }
+
+ ///
+ public string IP { get; private set; }
+
+ ///
+ public Socket MainSocket { get; private set; }
+
+ ///
+ public bool Online { get => this.m_online; }
+
+ ///
+ public bool CanSend => this.m_online;
+
+ ///
+ public IPluginsManager PluginsManager { get; private set; }
+
+ ///
+ public int Port { get; private set; }
+
+
+
+ ///
+ public bool UseSsl => this.GetTcpCore().UseSsl;
+
+ ///
+ public Protocol Protocol { get; set; }
+
+ ///
+ public IPHost RemoteIPHost { get; private set; }
+
+ ///
+ public bool IsClient => true;
+
+ #endregion 属性
+
+ #region 断开操作
+
+ ///
+ public virtual void Close(string msg = TouchSocketCoreUtility.Empty)
+ {
+ lock (this.SyncRoot)
+ {
+ if (this.m_online)
+ {
+ Task.Factory.StartNew(this.PrivateOnDisconnecting, new DisconnectEventArgs(true, msg));
+ this.MainSocket.TryClose();
+ this.BreakOut(default, true, msg);
+ }
+ }
+ }
+
+
+ ///
+ ///
+ ///
+ ///
+ protected override void Dispose(bool disposing)
+ {
+ lock (this.SyncRoot)
+ {
+ if (this.m_online)
+ {
+ Task.Factory.StartNew(this.PrivateOnDisconnecting, new DisconnectEventArgs(true, $"{nameof(Dispose)}主动断开"));
+ this.BreakOut(default, true, $"{nameof(Dispose)}主动断开");
+ }
+ }
+ base.Dispose(disposing);
+ }
+
+ #endregion 断开操作
+
+ #region Connect
+
+ ///
+ /// 建立Tcp的连接。
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ protected void TcpConnect(int timeout)
+ {
+ lock (this.SyncRoot)
+ {
+ if (this.m_online)
+ {
+ return;
+ }
+ if (this.DisposedValue)
+ {
+ throw new ObjectDisposedException(this.GetType().FullName);
+ }
+ if (this.Config == null)
+ {
+ throw new ArgumentNullException(nameof(this.Config), "配置文件不能为空。");
+ }
+ var iPHost = this.Config.GetValue(TouchSocketConfigExtension.RemoteIPHostProperty) ?? throw new ArgumentNullException(nameof(IPHost), "iPHost不能为空。");
+ this.MainSocket.SafeDispose();
+ var socket = this.CreateSocket(iPHost);
+ this.PrivateOnConnecting(new ConnectingEventArgs(socket))
+ .ConfigureAwait(false)
+ .GetAwaiter()
+ .GetResult();
+ if (timeout == 5000)
+ {
+ socket.Connect(iPHost.Host, iPHost.Port);
+ }
+ else
+ {
+ var task = Task.Run(() =>
+ {
+ socket.Connect(iPHost.Host, iPHost.Port);
+ });
+ task.ConfigureAwait(false);
+ if (!task.Wait(timeout))
+ {
+ socket.SafeDispose();
+ throw new TimeoutException();
+ }
+ }
+ this.m_online = true;
+ this.SetSocket(socket);
+ this.BeginReceive();
+ this.PrivateOnConnected(new ConnectedEventArgs())
+ .ConfigureAwait(false)
+ .GetAwaiter()
+ .GetResult();
+ }
+ }
+
+ private void BeginReceive()
+ {
+ if (this.Config.GetValue(TouchSocketConfigExtension.SslOptionProperty) is ClientSslOption sslOption)
+ {
+ this.GetTcpCore().Authenticate(sslOption);
+ _ = this.GetTcpCore().BeginSslReceive();
+ }
+ else
+ {
+ this.GetTcpCore().BeginIocpReceive();
+ }
+ }
+
+
+ ///
+ /// 异步连接服务器
+ ///
+ protected async Task TcpConnectAsync(int timeout, CancellationToken cancellationToken = default)
+ {
+ try
+ {
+ 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), "配置文件不能为空。");
+ }
+ var iPHost = this.Config.GetValue(TouchSocketConfigExtension.RemoteIPHostProperty) ?? throw new ArgumentNullException(nameof(IPHost), "iPHost不能为空。");
+ this.MainSocket.SafeDispose();
+ var socket = this.CreateSocket(iPHost);
+ await this.PrivateOnConnecting(new ConnectingEventArgs(socket));
+
+#if NET6_0_OR_GREATER
+ using CancellationTokenSource cancellationTokenSource = new(timeout);
+ using CancellationTokenSource stoppingToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationTokenSource.Token, cancellationToken);
+ try
+ {
+ await socket.ConnectAsync(iPHost.EndPoint, stoppingToken.Token);
+ }
+ catch (OperationCanceledException)
+ {
+ throw new TimeoutException("连接超时");
+ }
+ await SuccessAsync(socket);
+#else
+
+ using CancellationTokenSource cancellationTokenSource = new();
+ using CancellationTokenSource stoppingToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationTokenSource.Token, cancellationToken);
+ var task = Task.Factory.FromAsync(socket.BeginConnect(iPHost.EndPoint, null, null), socket.EndConnect);
+ var result = await Task.WhenAny(task, Task.Delay(timeout, stoppingToken.Token));
+ if (result == task)
+ {
+ cancellationTokenSource.Cancel();
+ if (task.Exception != null)
+ {
+ socket?.SafeDispose();
+ throw task.Exception;
+ }
+ else
+ {
+ await SuccessAsync(socket);
+ }
+ }
+ else
+ {
+ socket?.SafeDispose();
+ throw new TimeoutException("连接超时");
+ }
+
+
+
+
+#endif
+ async Task SuccessAsync(Socket socket)
+ {
+ this.m_online = true;
+ this.SetSocket(socket);
+ this.BeginReceive();
+ await (this.PrivateOnConnected(new ConnectedEventArgs()));
+ }
+ }
+ finally
+ {
+ this.m_semaphore.Release();
+ }
+ }
+
+
+ ///
+ public virtual ITcpClient Connect(int timeout = 5000)
+ {
+ this.TcpConnect(timeout);
+ return this;
+ }
+
+ ///
+ public virtual async Task ConnectAsync(int timeout = 5000)
+ {
+ await this.TcpConnectAsync(timeout);
+ return this;
+ }
+ ///
+ public virtual async Task ConnectAsync(int timeout, CancellationToken cancellationToken)
+ {
+ await TcpConnectAsync(timeout, cancellationToken);
+ return this;
+ }
+
+ #endregion Connect
+
+ #region Receiver
+
+ private Receiver m_receiver;
+
+ ///
+ public IReceiver CreateReceiver()
+ {
+ return this.m_receiver ??= new Receiver(this);
+ }
+
+ ///
+ public void ClearReceiver()
+ {
+ this.m_receiver = null;
+ }
+
+ #endregion
+
+ private void BreakOut(TcpCore core, bool manual, string msg)
+ {
+ lock (this.SyncRoot)
+ {
+ if (this.m_online)
+ {
+ this.m_online = false;
+ this.MainSocket.SafeDispose();
+ this.m_delaySender.SafeDispose();
+ this.DataHandlingAdapter.SafeDispose();
+ Task.Factory.StartNew(this.PrivateOnDisconnected, new DisconnectEventArgs(manual, msg));
+ }
+ }
+ }
+
+ private TcpCore GetTcpCore()
+ {
+ this.ThrowIfDisposed();
+ return this.m_tcpCore ?? throw new ObjectDisposedException(this.GetType().Name);
+ }
+
+
+ ///
+ public override int ReceiveBufferSize
+ {
+ get => this.GetTcpCore().ReceiveBufferSize;
+ set
+ {
+ this.GetTcpCore().ReceiveBufferSize = value;
+ }
+ }
+
+ ///
+ public override int SendBufferSize
+ {
+ get => this.GetTcpCore().SendBufferSize;
+ set
+ {
+ this.GetTcpCore().SendBufferSize = value;
+ }
+ }
+
+ ///
+ public virtual void SetDataHandlingAdapter(SingleStreamDataHandlingAdapter adapter)
+ {
+ if (!this.CanSetDataHandlingAdapter)
+ {
+ throw new Exception($"不允许自由调用{nameof(SetDataHandlingAdapter)}进行赋值。");
+ }
+
+ this.SetAdapter(adapter);
+ }
+
+ ///
+ 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();
+ }
+
+ if (!(config.GetValue(TouchSocketCoreConfigExtension.PluginsManagerProperty) is IPluginsManager pluginsManager))
+ {
+ pluginsManager = new PluginsManager(container);
+ }
+
+ if (container.IsRegistered(typeof(IPluginsManager)))
+ {
+ pluginsManager = container.Resolve();
+ }
+ else
+ {
+ container.RegisterSingleton(pluginsManager);
+ }
+
+ if (config.GetValue(TouchSocketCoreConfigExtension.ConfigureContainerProperty) is Action actionContainer)
+ {
+ actionContainer.Invoke(container);
+ }
+
+ if (config.GetValue(TouchSocketCoreConfigExtension.ConfigurePluginsProperty) is Action 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)
+ {
+ if (this.m_receiver.TryInputReceive(byteBlock, requestInfo))
+ {
+ return;
+ }
+ }
+ this.ReceivedData(new ReceivedDataEventArgs(byteBlock, requestInfo)).GetFalseAwaitResult();
+ }
+
+ ///
+ /// 当收到适配器处理的数据时。
+ ///
+ ///
+ /// 如果返回则表示数据已被处理,且不会再向下传递。
+ protected virtual Task ReceivedData(ReceivedDataEventArgs e)
+ {
+ return this.PluginsManager.RaiseAsync(nameof(ITcpReceivedPlugin.OnTcpReceived), this, e);
+ }
+
+
+ ///
+ /// 当即将发送时,如果覆盖父类方法,则不会触发插件。
+ ///
+ /// 数据缓存区
+ /// 偏移
+ /// 长度
+ /// 返回值表示是否允许发送
+ protected virtual async Task SendingData(byte[] buffer, int offset, int length)
+ {
+ 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);
+ return args.IsPermitOperation;
+ }
+ return true;
+ }
+
+ ///
+ /// 加载配置
+ ///
+ ///
+ protected virtual void LoadConfig(TouchSocketConfig config)
+ {
+ this.RemoteIPHost = config.GetValue(TouchSocketConfigExtension.RemoteIPHostProperty);
+ this.Logger ??= this.Container.Resolve();
+ }
+
+ ///
+ /// 设置适配器,该方法不会检验的值。
+ ///
+ ///
+ protected void SetAdapter(SingleStreamDataHandlingAdapter adapter)
+ {
+ this.ThrowIfDisposed();
+ if (adapter is null)
+ {
+ throw new ArgumentNullException(nameof(adapter));
+ }
+
+ if (this.Config != null)
+ {
+ adapter.Config(this.Config);
+ }
+
+ adapter.Logger = this.Logger;
+ adapter.OnLoaded(this);
+ adapter.ReceivedCallBack = this.PrivateHandleReceivedData;
+ adapter.SendCallBack = this.DefaultSend;
+ adapter.SendAsyncCallBack = this.DefaultSendAsync;
+ this.DataHandlingAdapter = adapter;
+ }
+
+ private Socket CreateSocket(IPHost iPHost)
+ {
+ Socket socket;
+ if (iPHost.HostNameType == UriHostNameType.Dns)
+ {
+ socket = new Socket(SocketType.Stream, ProtocolType.Tcp)
+ {
+ SendTimeout = this.Config.GetValue(TouchSocketConfigExtension.SendTimeoutProperty)
+ };
+ }
+ else
+ {
+ socket = new Socket(iPHost.EndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp)
+ {
+ SendTimeout = this.Config.GetValue(TouchSocketConfigExtension.SendTimeoutProperty)
+ };
+ }
+ if (this.Config.GetValue(TouchSocketConfigExtension.KeepAliveValueProperty) is KeepAliveValue keepAliveValue)
+ {
#if NET45_OR_GREATER
- socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
- socket.IOControl(IOControlCode.KeepAliveValues, keepAliveValue.KeepAliveTime, null);
-#else
- if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
- {
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
socket.IOControl(IOControlCode.KeepAliveValues, keepAliveValue.KeepAliveTime, null);
- }
+#else
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
+ socket.IOControl(IOControlCode.KeepAliveValues, keepAliveValue.KeepAliveTime, null);
+ }
#endif
- }
-
- var noDelay = this.Config.GetValue(TouchSocketConfigExtension.NoDelayProperty);
- if (noDelay != null)
- {
- socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, noDelay);
- }
-
- if (this.Config.GetValue(TouchSocketConfigExtension.BindIPHostProperty) != null)
- {
- if (this.Config.GetValue(TouchSocketConfigExtension.ReuseAddressProperty))
- {
- socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
}
- socket.Bind(this.Config.GetValue(TouchSocketConfigExtension.BindIPHostProperty).EndPoint);
- }
- return socket;
- }
- private void EventArgs_Completed(object sender, SocketAsyncEventArgs e)
- {
- try
- {
- this.m_bufferRate = 1;
- this.ProcessReceived(e);
- }
- catch (Exception ex)
- {
- e.SafeDispose();
- this.BreakOut(ex.Message);
- }
- }
-
- ///
- /// 处理数据
- ///
- private void HandleBuffer(ByteBlock byteBlock)
- {
- try
- {
- this.m_receiveCounter.Increment(byteBlock.Length);
- if (this.OnHandleRawBuffer?.Invoke(byteBlock) == false)
+ var noDelay = this.Config.GetValue(TouchSocketConfigExtension.NoDelayProperty);
+ if (noDelay != null)
{
- return;
+ socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, noDelay);
}
+
+ if (this.Config.GetValue(TouchSocketConfigExtension.BindIPHostProperty) != null)
+ {
+ if (this.Config.GetValue(TouchSocketConfigExtension.ReuseAddressProperty))
+ {
+ socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
+ }
+ socket.Bind(this.Config.GetValue(TouchSocketConfigExtension.BindIPHostProperty).EndPoint);
+ }
+ return socket;
+ }
+
+ #region 发送
+
+ #region 同步发送
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public void Send(IRequestInfo requestInfo)
+ {
if (this.DisposedValue)
{
return;
}
- if (this.PluginsManager.Enable && this.PluginsManager.Raise(nameof(ITcpReceivingPlugin.OnTcpReceiving), this, new ByteBlockEventArgs(byteBlock)))
- {
- return;
- }
if (this.DataHandlingAdapter == null)
{
- this.Logger.Error(this, TouchSocketResource.NullDataAdapter.GetDescription());
- return;
+ throw new ArgumentNullException(nameof(this.DataHandlingAdapter), TouchSocketResource.NullDataAdapter.GetDescription());
}
- this.DataHandlingAdapter.ReceivedInput(byteBlock);
- }
- catch (Exception ex)
- {
- this.Logger.Log(LogLevel.Error, this, "在处理数据时发生错误", ex);
- }
- finally
- {
- byteBlock.Dispose();
- }
- }
- private void HandleBuffer(TcpCore core, ByteBlock byteBlock)
- {
- this.ThrowIfDisposed();
- if (this.OnHandleRawBuffer?.Invoke(byteBlock) == false)
- {
- return;
- }
-
- if (this.PluginsManager.Enable && this.PluginsManager.Raise(nameof(ITcpReceivingPlugin.OnTcpReceiving), this, new ByteBlockEventArgs(byteBlock)))
- {
- return;
- }
- if (this.DataHandlingAdapter == null)
- {
- this.Logger.Error(this, TouchSocketResource.NullDataAdapter.GetDescription());
- return;
- }
- this.DataHandlingAdapter.ReceivedInput(byteBlock);
- }
- #region 发送
-
- #region 同步发送
-
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- public void Send(IRequestInfo requestInfo)
- {
- if (this.DisposedValue)
- {
- return;
- }
- if (this.DataHandlingAdapter == null)
- {
- throw new ArgumentNullException(nameof(this.DataHandlingAdapter), TouchSocketResource.NullDataAdapter.GetDescription());
- }
- if (!this.DataHandlingAdapter.CanSendRequestInfo)
- {
- throw new NotSupportedException($"当前适配器不支持对象发送。");
- }
- this.DataHandlingAdapter.SendInput(requestInfo);
- }
-
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- public virtual void Send(byte[] buffer, int offset, int length)
- {
- if (this.DataHandlingAdapter == null)
- {
- throw new ArgumentNullException(nameof(this.DataHandlingAdapter), TouchSocketResource.NullDataAdapter.GetDescription());
- }
- this.DataHandlingAdapter.SendInput(buffer, offset, length);
- }
-
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- public virtual void Send(IList> transferBytes)
- {
- if (this.DataHandlingAdapter == null)
- {
- throw new ArgumentNullException(nameof(this.DataHandlingAdapter), TouchSocketResource.NullDataAdapter.GetDescription());
- }
-
- if (this.DataHandlingAdapter.CanSplicingSend)
- {
- this.DataHandlingAdapter.SendInput(transferBytes);
- }
- else
- {
- var length = 0;
- foreach (var item in transferBytes)
+ if (!this.DataHandlingAdapter.CanSendRequestInfo)
{
- length += item.Count;
+ throw new NotSupportedException($"当前适配器不支持对象发送。");
}
- using (var byteBlock = new ByteBlock(length))
+ this.DataHandlingAdapter.SendInput(requestInfo);
+ }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public virtual void Send(byte[] buffer, int offset, int length)
+ {
+ if (this.DataHandlingAdapter == null)
{
- foreach (var item in transferBytes)
- {
- byteBlock.Write(item.Array, item.Offset, item.Count);
- }
- this.DataHandlingAdapter.SendInput(byteBlock.Buffer, 0, byteBlock.Len);
+ throw new ArgumentNullException(nameof(this.DataHandlingAdapter), TouchSocketResource.NullDataAdapter.GetDescription());
}
+ this.DataHandlingAdapter.SendInput(buffer, offset, length);
}
- }
- #endregion 同步发送
-
- #region 异步发送
-
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- public virtual Task SendAsync(byte[] buffer, int offset, int length)
- {
- return Task.Run(() =>
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public virtual void Send(IList> transferBytes)
{
- this.Send(buffer, offset, length);
- });
- }
-
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- public virtual Task SendAsync(IRequestInfo requestInfo)
- {
- return Task.Run(() =>
- {
- this.Send(requestInfo);
- });
- }
-
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- public virtual Task SendAsync(IList> transferBytes)
- {
- return Task.Run(() =>
- {
- this.Send(transferBytes);
- });
- }
-
- #endregion 异步发送
-
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- public void DefaultSend(byte[] buffer, int offset, int length)
- {
- if (!this.m_online)
- {
- throw new NotConnectedException(TouchSocketResource.NotConnected.GetDescription());
- }
- if (this.HandleSendingData(buffer, offset, length))
- {
- if (this.UseSsl)
+ if (this.DataHandlingAdapter == null)
{
- this.m_workStream.Write(buffer, offset, length);
+ throw new ArgumentNullException(nameof(this.DataHandlingAdapter), TouchSocketResource.NullDataAdapter.GetDescription());
+ }
+
+ if (this.DataHandlingAdapter.CanSplicingSend)
+ {
+ this.DataHandlingAdapter.SendInput(transferBytes);
}
else
{
- if (this.m_delaySender != null && length < this.m_delaySender.DelayLength)
+ var length = 0;
+ foreach (var item in transferBytes)
{
- this.m_delaySender.Send(QueueDataBytes.CreateNew(buffer, offset, length));
+ length += item.Count;
}
- else
+ using (var byteBlock = new ByteBlock(length))
{
- this.MainSocket.AbsoluteSend(buffer, offset, length);
+ foreach (var item in transferBytes)
+ {
+ byteBlock.Write(item.Array, item.Offset, item.Count);
+ }
+ this.DataHandlingAdapter.SendInput(byteBlock.Buffer, 0, byteBlock.Len);
}
}
- this.m_sendCounter.Increment(length);
- }
- }
-
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- public Task DefaultSendAsync(byte[] buffer, int offset, int length)
- {
- return Task.Run(() =>
- {
- this.DefaultSend(buffer, offset, length);
- });
- }
-
- #endregion 发送
-
- private void SetSocket(Socket socket)
- {
- if (socket == null)
- {
- this.IP = null;
- this.Port = -1;
- return;
}
- this.IP = socket.RemoteEndPoint.GetIP();
- this.Port = socket.RemoteEndPoint.GetPort();
- this.MainSocket = socket;
- var delaySenderOption = this.Config.GetValue(TouchSocketConfigExtension.DelaySenderProperty);
- if (delaySenderOption != null)
- {
- this.m_delaySender = new DelaySender(delaySenderOption, this.MainSocket.AbsoluteSend);
- }
- }
+ #endregion 同步发送
- private void ProcessReceived(SocketAsyncEventArgs e)
- {
- if (!this.m_online)
+ #region 异步发送
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public virtual Task SendAsync(byte[] buffer, int offset, int length)
{
- e.SafeDispose();
- return;
+ this.ThrowIfDisposed();
+ if (this.DataHandlingAdapter == null)
+ {
+ throw new ArgumentNullException(nameof(this.DataHandlingAdapter), TouchSocketResource.NullDataAdapter.GetDescription());
+ }
+ return this.DataHandlingAdapter.SendInputAsync(buffer, offset, length);
}
- if (e.SocketError != SocketError.Success)
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public virtual Task SendAsync(IRequestInfo requestInfo)
{
- e.SafeDispose();
- this.BreakOut(e.SocketError.ToString());
- return;
+ this.ThrowIfDisposed();
+ if (this.DataHandlingAdapter == null)
+ {
+ throw new ArgumentNullException(nameof(this.DataHandlingAdapter), TouchSocketResource.NullDataAdapter.GetDescription());
+ }
+ if (!this.DataHandlingAdapter.CanSendRequestInfo)
+ {
+ throw new NotSupportedException($"当前适配器不支持对象发送。");
+ }
+ return this.DataHandlingAdapter.SendInputAsync(requestInfo);
}
- else if (e.BytesTransferred > 0)
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public virtual Task SendAsync(IList> transferBytes)
+ {
+ this.ThrowIfDisposed();
+ if (this.DataHandlingAdapter == null)
+ {
+ throw new ArgumentNullException(nameof(this.DataHandlingAdapter), TouchSocketResource.NullDataAdapter.GetDescription());
+ }
+ if (this.DataHandlingAdapter.CanSplicingSend)
+ {
+ return this.DataHandlingAdapter.SendInputAsync(transferBytes);
+ }
+ else
+ {
+ var length = 0;
+ foreach (var item in transferBytes)
+ {
+ length += item.Count;
+ }
+ using (var byteBlock = new ByteBlock(length))
+ {
+ foreach (var item in transferBytes)
+ {
+ byteBlock.Write(item.Array, item.Offset, item.Count);
+ }
+ return this.DataHandlingAdapter.SendInputAsync(byteBlock.Buffer, 0, byteBlock.Len);
+ }
+ }
+ }
+
+ #endregion 异步发送
+
+ ///
+ public void DefaultSend(byte[] buffer, int offset, int length)
+ {
+ if (this.SendingData(buffer, offset, length).GetFalseAwaitResult())
+ {
+ this.GetTcpCore().Send(buffer, offset, length);
+ }
+ }
+
+ ///
+ public async Task DefaultSendAsync(byte[] buffer, int offset, int length)
+ {
+ if (await this.SendingData(buffer, offset, length))
+ {
+ await this.GetTcpCore().SendAsync(buffer, offset, length);
+ }
+ }
+
+ #endregion 发送
+
+ private void SetSocket(Socket socket)
+ {
+ if (socket == null)
+ {
+ this.IP = null;
+ this.Port = -1;
+ return;
+ }
+
+ this.IP = socket.RemoteEndPoint.GetIP();
+ this.Port = socket.RemoteEndPoint.GetPort();
+ this.MainSocket = socket;
+ var delaySenderOption = this.Config.GetValue(TouchSocketConfigExtension.DelaySenderProperty);
+ if (delaySenderOption != null)
+ {
+ this.m_delaySender = new DelaySender(delaySenderOption, this.MainSocket.AbsoluteSend);
+ }
+ this.m_tcpCore.Reset(socket);
+ this.m_tcpCore.OnReceived = this.HandleReceived;
+ this.m_tcpCore.OnBreakOut = this.BreakOut;
+
+ }
+
+ private void HandleReceived(TcpCore core, ByteBlock byteBlock)
{
- var byteBlock = (ByteBlock)e.UserToken;
- byteBlock.SetLength(e.BytesTransferred);
- this.HandleBuffer(byteBlock);
try
{
- var newByteBlock = BytePool.Default.GetByteBlock((int)Math.Min(this.ReceiveBufferSize * this.m_bufferRate, TouchSocketUtility.MaxBufferLength));
- e.UserToken = newByteBlock;
- e.SetBuffer(newByteBlock.Buffer, 0, newByteBlock.Capacity);
-
- if (!this.MainSocket.ReceiveAsync(e))
+ if (this.DisposedValue)
{
- this.m_bufferRate += 2;
- this.ProcessReceived(e);
+ return;
}
+ if (this.ReceivingData(byteBlock).GetFalseAwaitResult())
+ {
+ return;
+ }
+
+ if (this.DataHandlingAdapter == null)
+ {
+ this.Logger.Error(this, TouchSocketResource.NullDataAdapter.GetDescription());
+ return;
+ }
+ this.DataHandlingAdapter.ReceivedInput(byteBlock);
}
catch (Exception ex)
{
- e.SafeDispose();
- this.BreakOut(ex.Message);
+ this.Logger.Log(LogLevel.Error, this, "在处理数据时发生错误", ex);
}
}
- else
+
+ ///
+ /// 当收到原始数据
+ ///
+ ///
+ /// 如果返回则表示数据已被处理,且不会再向下传递。
+ protected virtual Task ReceivingData(ByteBlock byteBlock)
{
- e.SafeDispose();
- this.BreakOut("远程终端主动关闭");
+ if (this.PluginsManager.GetPluginCount(nameof(ITcpReceivingPlugin.OnTcpReceiving)) > 0)
+ {
+ return this.PluginsManager.RaiseAsync(nameof(ITcpReceivingPlugin.OnTcpReceiving), this, new ByteBlockEventArgs(byteBlock));
+ }
+ return Task.FromResult(false);
}
- }
- ///
- ///
- ///
- ///
- public override string ToString()
- {
- return this.GetIPPort();
+
+
}
}
\ No newline at end of file
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Components/Tcp/TcpService.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Components/Tcp/TcpService.cs
index bf121a4b2..f6b8c4280 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Components/Tcp/TcpService.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Components/Tcp/TcpService.cs
@@ -27,11 +27,10 @@ using System.Net.Sockets;
namespace ThingsGateway.Foundation.Sockets
{
///
- /// TCP泛型服务器,由使用者自己指定类型。
+ /// Tcp泛型服务器,由使用者自己指定类型。
///
public class TcpService : TcpServiceBase, ITcpService where TClient : SocketClient, new()
{
-
///
/// 构造函数
///
@@ -102,25 +101,17 @@ namespace ThingsGateway.Foundation.Sockets
///
/// 即将断开连接(仅主动断开时有效)。
- ///
- /// 当主动调用Close断开时,可通过终止断开行为。
- ///
///
public DisconnectEventHandler Disconnecting { get; set; }
- ///
- /// 当客户端Id被修改时触发。
- ///
- public IdChangedEventHandler IdChanged { get; set; }
-
///
///
///
///
///
- protected override sealed void OnClientConnected(ISocketClient socketClient, ConnectedEventArgs e)
+ protected override sealed Task OnClientConnected(ISocketClient socketClient, ConnectedEventArgs e)
{
- this.OnConnected((TClient)socketClient, e);
+ return this.OnConnected((TClient)socketClient, e);
}
///
@@ -128,9 +119,9 @@ namespace ThingsGateway.Foundation.Sockets
///
///
///
- protected override sealed void OnClientConnecting(ISocketClient socketClient, ConnectingEventArgs e)
+ protected override sealed Task OnClientConnecting(ISocketClient socketClient, ConnectingEventArgs e)
{
- this.OnConnecting((TClient)socketClient, e);
+ return this.OnConnecting((TClient)socketClient, e);
}
///
@@ -138,9 +129,9 @@ namespace ThingsGateway.Foundation.Sockets
///
///
///
- protected override sealed void OnClientDisconnected(ISocketClient socketClient, DisconnectEventArgs e)
+ protected override sealed Task OnClientDisconnected(ISocketClient socketClient, DisconnectEventArgs e)
{
- this.OnDisconnected((TClient)socketClient, e);
+ return this.OnDisconnected((TClient)socketClient, e);
}
///
@@ -148,20 +139,19 @@ namespace ThingsGateway.Foundation.Sockets
///
///
///
- protected override sealed void OnClientDisconnecting(ISocketClient socketClient, DisconnectEventArgs e)
+ protected override sealed Task OnClientDisconnecting(ISocketClient socketClient, DisconnectEventArgs e)
{
- this.OnDisconnecting((TClient)socketClient, e);
+ return this.OnDisconnecting((TClient)socketClient, e);
}
///
///
///
///
- ///
- ///
- protected override sealed void OnClientReceivedData(ISocketClient socketClient, ByteBlock byteBlock, IRequestInfo requestInfo)
+ ///
+ protected override sealed Task OnClientReceivedData(ISocketClient socketClient, ReceivedDataEventArgs e)
{
- this.OnReceived((TClient)socketClient, byteBlock, requestInfo);
+ return this.OnReceived((TClient)socketClient, e);
}
///
@@ -169,9 +159,13 @@ namespace ThingsGateway.Foundation.Sockets
///
///
///
- protected virtual void OnConnected(TClient socketClient, ConnectedEventArgs e)
+ protected virtual Task OnConnected(TClient socketClient, ConnectedEventArgs e)
{
- this.Connected?.Invoke(socketClient, e);
+ if (this.Connected != null)
+ {
+ return this.Connected.Invoke(socketClient, e);
+ }
+ return EasyTask.CompletedTask;
}
///
@@ -179,9 +173,13 @@ namespace ThingsGateway.Foundation.Sockets
///
///
///
- protected virtual void OnConnecting(TClient socketClient, ConnectingEventArgs e)
+ protected virtual Task OnConnecting(TClient socketClient, ConnectingEventArgs e)
{
- this.Connecting?.Invoke(socketClient, e);
+ if (this.Connecting != null)
+ {
+ return this.Connecting.Invoke(socketClient, e);
+ }
+ return EasyTask.CompletedTask;
}
///
@@ -189,32 +187,37 @@ namespace ThingsGateway.Foundation.Sockets
///
///
///
- protected virtual void OnDisconnected(TClient socketClient, DisconnectEventArgs e)
+ protected virtual Task OnDisconnected(TClient socketClient, DisconnectEventArgs e)
{
- this.Disconnected?.Invoke(socketClient, e);
+ if (this.Disconnected != null)
+ {
+ return this.Disconnected.Invoke(socketClient, e);
+ }
+ return EasyTask.CompletedTask;
}
///
/// 即将断开连接(仅主动断开时有效)。
- ///
- /// 当主动调用Close断开时,可通过终止断开行为。
- ///
///
///
///
- protected virtual void OnDisconnecting(TClient socketClient, DisconnectEventArgs e)
+ protected virtual Task OnDisconnecting(TClient socketClient, DisconnectEventArgs e)
{
- this.Disconnecting?.Invoke(socketClient, e);
+ if (this.Disconnected != null)
+ {
+ return this.Disconnecting.Invoke(socketClient, e);
+ }
+ return EasyTask.CompletedTask;
}
///
/// 当收到适配器数据。
///
///
- ///
- ///
- protected virtual void OnReceived(TClient socketClient, ByteBlock byteBlock, IRequestInfo requestInfo)
+ ///
+ protected virtual Task OnReceived(TClient socketClient, ReceivedDataEventArgs e)
{
+ return EasyTask.CompletedTask;
}
#endregion 事件
@@ -224,7 +227,6 @@ namespace ThingsGateway.Foundation.Sockets
return Interlocked.Increment(ref this.m_nextId).ToString();
}
-
///
/// 获取下一个新Id
///
@@ -363,7 +365,6 @@ namespace ThingsGateway.Foundation.Sockets
///
public override IService Setup(TouchSocketConfig config)
{
-
if (config == null)
{
throw new ArgumentNullException(nameof(config));
@@ -434,7 +435,6 @@ namespace ThingsGateway.Foundation.Sockets
ReuseAddress = this.Config.GetValue(TouchSocketConfigExtension.ReuseAddressProperty),
NoDelay = this.Config.GetValue(TouchSocketConfigExtension.NoDelayProperty),
Adapter = this.Config.GetValue(TouchSocketConfigExtension.TcpDataHandlingAdapterProperty),
- ReceiveType = this.Config.GetValue(TouchSocketConfigExtension.ReceiveTypeProperty)
};
option.Backlog = this.Config.GetValue(TouchSocketConfigExtension.BacklogProperty) ?? option.Backlog;
option.SendTimeout = this.Config.GetValue(TouchSocketConfigExtension.SendTimeoutProperty);
@@ -540,11 +540,11 @@ namespace ThingsGateway.Foundation.Sockets
this.Clear();
this.m_serverState = ServerState.Disposed;
- if (this.PluginsManager?.Enable == true)
+ if (this.PluginsManager.Enable)
{
this.m_pluginsManager.Raise(nameof(IServerStopedPlugin.OnServerStoped), this, new ServiceStateEventArgs(this.m_serverState, default));
}
- this.PluginsManager?.SafeDispose();
+ this.PluginsManager.SafeDispose();
}
base.Dispose(disposing);
}
@@ -691,7 +691,7 @@ namespace ThingsGateway.Foundation.Sockets
return new NormalDataHandlingAdapter();
}
- private void OnClientSocketInit(object obj)
+ private async Task OnClientSocketInit(object obj)
{
var tuple = (Tuple)obj;
var socket = tuple.Item1;
@@ -717,30 +717,35 @@ namespace ThingsGateway.Foundation.Sockets
{
client.SetDataHandlingAdapter(this.GetAdapter(monitor));
}
- client.InternalInitialized();
+
+ await client.InternalInitialized();
var args = new ConnectingEventArgs(socket)
{
Id = this.GetNextNewId()
};
- client.InternalConnecting(args);//Connecting
+ await client.InternalConnecting(args);//Connecting
if (args.IsPermitOperation)
{
client.InternalSetId(args.Id);
- if (!client.MainSocket.Connected)
+ if (!socket.Connected)
{
- client.MainSocket.SafeDispose();
+ socket.SafeDispose();
return;
}
if (this.m_socketClients.TryAdd(client))
{
- client.InternalConnected(new ConnectedEventArgs());
-
+ _ = client.InternalConnected(new ConnectedEventArgs());
+ if (!socket.Connected)
+ {
+ return;
+ }
if (monitor.Option.UseSsl)
{
try
{
- client.BeginReceiveSsl(monitor.Option.ServiceSslOption);
+ await client.AuthenticateAsync(monitor.Option.ServiceSslOption);
+ _ = client.BeginReceiveSsl();
}
catch (Exception ex)
{
@@ -772,7 +777,7 @@ namespace ThingsGateway.Foundation.Sockets
}
///
- /// TCP服务器
+ /// Tcp服务器
///
public class TcpService : TcpService
{
@@ -781,16 +786,14 @@ namespace ThingsGateway.Foundation.Sockets
///
public ReceivedEventHandler Received { get; set; }
- ///
///
- ///
- ///
- ///
- ///
- protected override void OnReceived(SocketClient socketClient, ByteBlock byteBlock, IRequestInfo requestInfo)
+ protected override Task OnReceived(SocketClient socketClient, ReceivedDataEventArgs e)
{
- this.Received?.Invoke(socketClient, byteBlock, requestInfo);
- base.OnReceived(socketClient, byteBlock, requestInfo);
+ if (this.Received != null)
+ {
+ return this.Received.Invoke(socketClient, e);
+ }
+ return EasyTask.CompletedTask;
}
}
}
\ No newline at end of file
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Components/Tcp/TcpServiceBase.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Components/Tcp/TcpServiceBase.cs
index 17781af74..6b7c88d65 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Components/Tcp/TcpServiceBase.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Components/Tcp/TcpServiceBase.cs
@@ -22,6 +22,7 @@
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
+using System.Collections.Concurrent;
namespace ThingsGateway.Foundation.Sockets
{
@@ -122,29 +123,64 @@ namespace ThingsGateway.Foundation.Sockets
///
public abstract IService Stop();
- internal void OnInternalConnected(ISocketClient socketClient, ConnectedEventArgs e)
+ private ConcurrentStack m_tcpCores = new ConcurrentStack();
+
+ ///
+ /// 租用TcpCore
+ ///
+ ///
+ public TcpCore RentTcpCore()
{
- this.OnClientConnected(socketClient, e);
+ if (this.m_tcpCores.TryPop(out var tcpCore))
+ {
+ return tcpCore;
+ }
+
+ return new InternalTcpCore();
}
- internal void OnInternalConnecting(ISocketClient socketClient, ConnectingEventArgs e)
+ ///
+ protected override void Dispose(bool disposing)
{
- this.OnClientConnecting(socketClient, e);
+ while (this.m_tcpCores.TryPop(out var tcpCore))
+ {
+ tcpCore.SafeDispose();
+ }
+ base.Dispose(disposing);
}
- internal void OnInternalDisconnected(ISocketClient socketClient, DisconnectEventArgs e)
+ ///
+ /// 归还TcpCore
+ ///
+ ///
+ public void ReturnTcpCore(TcpCore tcpCore)
{
- this.OnClientDisconnected(socketClient, e);
+ this.m_tcpCores.Push(tcpCore);
}
- internal void OnInternalDisconnecting(ISocketClient socketClient, DisconnectEventArgs e)
+ internal Task OnInternalConnected(ISocketClient socketClient, ConnectedEventArgs e)
{
- this.OnClientDisconnecting(socketClient, e);
+ return this.OnClientConnected(socketClient, e);
}
- internal void OnInternalReceivedData(ISocketClient socketClient, ByteBlock byteBlock, IRequestInfo requestInfo)
+ internal Task OnInternalConnecting(ISocketClient socketClient, ConnectingEventArgs e)
{
- this.OnClientReceivedData(socketClient, byteBlock, requestInfo);
+ return this.OnClientConnecting(socketClient, e);
+ }
+
+ internal Task OnInternalDisconnected(ISocketClient socketClient, DisconnectEventArgs e)
+ {
+ return this.OnClientDisconnected(socketClient, e);
+ }
+
+ internal Task OnInternalDisconnecting(ISocketClient socketClient, DisconnectEventArgs e)
+ {
+ return this.OnClientDisconnecting(socketClient, e);
+ }
+
+ internal Task OnInternalReceivedData(ISocketClient socketClient, ReceivedDataEventArgs e)
+ {
+ return this.OnClientReceivedData(socketClient, e);
}
///
@@ -152,39 +188,35 @@ namespace ThingsGateway.Foundation.Sockets
///
///
///
- protected abstract void OnClientConnected(ISocketClient socketClient, ConnectedEventArgs e);
+ protected abstract Task OnClientConnected(ISocketClient socketClient, ConnectedEventArgs e);
///
/// 客户端请求连接
///
///
///
- protected abstract void OnClientConnecting(ISocketClient socketClient, ConnectingEventArgs e);
+ protected abstract Task OnClientConnecting(ISocketClient socketClient, ConnectingEventArgs e);
///
/// 客户端断开连接
///
///
///
- protected abstract void OnClientDisconnected(ISocketClient socketClient, DisconnectEventArgs e);
+ protected abstract Task OnClientDisconnected(ISocketClient socketClient, DisconnectEventArgs e);
///
/// 即将断开连接(仅主动断开时有效)。
- ///
- /// 当主动调用Close断开时,可通过终止断开行为。
- ///
///
///
///
- protected abstract void OnClientDisconnecting(ISocketClient socketClient, DisconnectEventArgs e);
+ protected abstract Task OnClientDisconnecting(ISocketClient socketClient, DisconnectEventArgs e);
///
/// 收到数据时
///
///
- ///
- ///
- protected abstract void OnClientReceivedData(ISocketClient socketClient, ByteBlock byteBlock, IRequestInfo requestInfo);
+ ///
+ protected abstract Task OnClientReceivedData(ISocketClient socketClient, ReceivedDataEventArgs e);
#region Id发送
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Components/Udp/UdpSession.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Components/Udp/UdpSession.cs
index ce7342b40..ad9f08bc8 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Components/Udp/UdpSession.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Components/Udp/UdpSession.cs
@@ -36,17 +36,20 @@ namespace ThingsGateway.Foundation.Sockets
///
/// 当收到数据时
///
- public UdpReceivedEventHandler Received { get; set; }
+ public UdpReceivedEventHandler Received { get; set; }
- ///
///
- ///
- ///
- ///
- ///
- protected override void HandleReceivedData(EndPoint remoteEndPoint, ByteBlock byteBlock, IRequestInfo requestInfo)
+ protected override async Task ReceivedData(UdpReceivedDataEventArgs e)
{
- this.Received?.Invoke(remoteEndPoint, byteBlock, requestInfo);
+ if (this.Received != null)
+ {
+ await this.Received.Invoke(this, e);
+ if (e.Handled)
+ {
+ return;
+ }
+ }
+ await base.ReceivedData(e);
}
}
@@ -70,16 +73,6 @@ namespace ThingsGateway.Foundation.Sockets
this.SendBufferSize = 1024 * 64;
}
- ///
- /// 处理未经过适配器的数据。返回值表示是否继续向下传递。
- ///
- public Func OnHandleRawBuffer { get; set; }
-
- ///
- /// 处理经过适配器后的数据。返回值表示是否继续向下传递。
- ///
- public Func OnHandleReceivedData { get; set; }
-
///
///
///
@@ -342,7 +335,6 @@ namespace ThingsGateway.Foundation.Sockets
this.PluginsManager.Raise(nameof(IServerStartedPlugin.OnServerStarted), this, new ServiceStateEventArgs(this.ServerState, ex) { Message = ex.Message });
throw;
}
-
}
///
@@ -391,11 +383,9 @@ namespace ThingsGateway.Foundation.Sockets
///
/// 处理已接收到的数据。
///
- ///
- /// 以二进制流形式传递
- /// 以解析的数据对象传递
- protected virtual void HandleReceivedData(EndPoint remoteEndPoint, ByteBlock byteBlock, IRequestInfo requestInfo)
+ protected virtual Task ReceivedData(UdpReceivedDataEventArgs e)
{
+ return this.PluginsManager.RaiseAsync(nameof(IUdpReceivedPlugin.OnUdpReceived), this, e);
}
///
@@ -492,7 +482,7 @@ namespace ThingsGateway.Foundation.Sockets
}
#endif
- #endregion
+ #endregion Windows下UDP连接被重置错误10054
this.PreviewBind(socket);
@@ -500,55 +490,48 @@ namespace ThingsGateway.Foundation.Sockets
this.Monitor = new UdpNetworkMonitor(iPHost, socket);
- switch (this.Config.GetValue(TouchSocketConfigExtension.ReceiveTypeProperty))
+
+#if NET45_OR_GREATER || NET6_0_OR_GREATER
+ for (var i = 0; i < threadCount; i++)
{
- case ReceiveType.Iocp:
- {
-#if NET45_OR_GREATER||NET6_0_OR_GREATER
- for (var i = 0; i < threadCount; i++)
- {
- var eventArg = new SocketAsyncEventArgs();
- this.m_socketAsyncs.Add(eventArg);
- eventArg.Completed += this.IO_Completed;
- var byteBlock = new ByteBlock(this.ReceiveBufferSize);
- eventArg.UserToken = byteBlock;
- eventArg.SetBuffer(byteBlock.Buffer, 0, byteBlock.Capacity);
- eventArg.RemoteEndPoint = iPHost.EndPoint;
- if (!socket.ReceiveFromAsync(eventArg))
- {
- this.ProcessReceive(socket, eventArg);
- }
- }
-#else
- if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
- {
- for (var i = 0; i < threadCount; i++)
- {
- var eventArg = new SocketAsyncEventArgs();
- this.m_socketAsyncs.Add(eventArg);
- eventArg.Completed += this.IO_Completed;
- var byteBlock = new ByteBlock(this.ReceiveBufferSize);
- eventArg.UserToken = byteBlock;
- eventArg.SetBuffer(byteBlock.Buffer, 0, byteBlock.Capacity);
- eventArg.RemoteEndPoint = iPHost.EndPoint;
- if (!socket.ReceiveFromAsync(eventArg))
- {
- this.ProcessReceive(socket, eventArg);
- }
- }
- }
- else
- {
- var thread = new Thread(this.Received);
- thread.IsBackground = true;
- thread.Start();
- }
-#endif
- break;
- }
- default:
- throw new Exception("UDP中只支持Auto模式");
+ var eventArg = new SocketAsyncEventArgs();
+ this.m_socketAsyncs.Add(eventArg);
+ eventArg.Completed += this.IO_Completed;
+ var byteBlock = new ByteBlock(this.ReceiveBufferSize);
+ eventArg.UserToken = byteBlock;
+ eventArg.SetBuffer(byteBlock.Buffer, 0, byteBlock.Capacity);
+ eventArg.RemoteEndPoint = iPHost.EndPoint;
+ if (!socket.ReceiveFromAsync(eventArg))
+ {
+ this.ProcessReceive(socket, eventArg);
+ }
}
+#else
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ for (var i = 0; i < threadCount; i++)
+ {
+ var eventArg = new SocketAsyncEventArgs();
+ this.m_socketAsyncs.Add(eventArg);
+ eventArg.Completed += this.IO_Completed;
+ var byteBlock = new ByteBlock(this.ReceiveBufferSize);
+ eventArg.UserToken = byteBlock;
+ eventArg.SetBuffer(byteBlock.Buffer, 0, byteBlock.Capacity);
+ eventArg.RemoteEndPoint = iPHost.EndPoint;
+ if (!socket.ReceiveFromAsync(eventArg))
+ {
+ this.ProcessReceive(socket, eventArg);
+ }
+ }
+ }
+ else
+ {
+ var thread = new Thread(this.Received);
+ thread.IsBackground = true;
+ thread.Start();
+ }
+#endif
+
}
private void Received()
@@ -577,10 +560,6 @@ namespace ThingsGateway.Foundation.Sockets
try
{
this.LastReceivedTime = DateTime.Now;
- if (this.OnHandleRawBuffer?.Invoke(byteBlock) == false)
- {
- return;
- }
if (this.DisposedValue)
{
return;
@@ -609,21 +588,14 @@ namespace ThingsGateway.Foundation.Sockets
private void PrivateHandleReceivedData(EndPoint remoteEndPoint, ByteBlock byteBlock, IRequestInfo requestInfo)
{
- if (this.OnHandleReceivedData?.Invoke(byteBlock, requestInfo) == false)
+ if (this.m_receiver != null)
{
- return;
- }
-
- if (this.PluginsManager.Enable)
- {
- var args = new UdpReceivedDataEventArgs(remoteEndPoint, byteBlock, requestInfo);
- this.PluginsManager.Raise(nameof(IUdpReceivedPlugin.OnUdpReceived), this, args);
- if (args.Handled)
+ if (this.m_receiver.TryInputReceive(byteBlock, requestInfo))
{
return;
}
}
- this.HandleReceivedData(remoteEndPoint, byteBlock, requestInfo);
+ this.ReceivedData(new UdpReceivedDataEventArgs(remoteEndPoint, byteBlock, requestInfo)).GetFalseAwaitResult();
}
#region 向默认远程同步发送
@@ -663,7 +635,7 @@ namespace ThingsGateway.Foundation.Sockets
{
throw new NotSupportedException($"当前适配器不支持对象发送。");
}
- this.DataHandlingAdapter.SendInput(requestInfo);
+ //this.DataHandlingAdapter.SendInput(requestInfo);
}
#endregion 向默认远程同步发送
@@ -682,9 +654,9 @@ namespace ThingsGateway.Foundation.Sockets
public virtual Task SendAsync(byte[] buffer, int offset, int length)
{
return Task.Run(() =>
- {
- this.Send(buffer, offset, length);
- });
+ {
+ this.Send(buffer, offset, length);
+ });
}
///
@@ -737,9 +709,9 @@ namespace ThingsGateway.Foundation.Sockets
public virtual Task SendAsync(EndPoint remoteEP, byte[] buffer, int offset, int length)
{
return Task.Run(() =>
- {
- this.Send(remoteEP, buffer, offset, length);
- });
+ {
+ this.Send(remoteEP, buffer, offset, length);
+ });
}
#endregion 向设置的远程异步发送
@@ -906,5 +878,23 @@ namespace ThingsGateway.Foundation.Sockets
}
#endregion 组合发送
+
+ #region Receiver
+
+ private Receiver m_receiver;
+
+ ///
+ public IReceiver CreateReceiver()
+ {
+ return this.m_receiver ??= new Receiver(this);
+ }
+
+ ///
+ public void ClearReceiver()
+ {
+ this.m_receiver = null;
+ }
+
+ #endregion
}
}
\ No newline at end of file
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/DataAdapter/Udp/NormalUdpDataHandlingAdapter.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/DataAdapter/Udp/NormalUdpDataHandlingAdapter.cs
index 4e57a1470..c2aac3201 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/DataAdapter/Udp/NormalUdpDataHandlingAdapter.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/DataAdapter/Udp/NormalUdpDataHandlingAdapter.cs
@@ -91,15 +91,6 @@ namespace ThingsGateway.Foundation.Sockets
}
}
- ///
- ///
- ///
- ///
- protected override void PreviewSend(IRequestInfo requestInfo)
- {
- throw new System.NotImplementedException();
- }
-
///
///
///
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/DataAdapter/Udp/UdpPackageAdapter.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/DataAdapter/Udp/UdpPackageAdapter.cs
index 5908d9d50..d2d5bff9a 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/DataAdapter/Udp/UdpPackageAdapter.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/DataAdapter/Udp/UdpPackageAdapter.cs
@@ -365,15 +365,6 @@ namespace ThingsGateway.Foundation.Sockets
}
}
- ///
- ///
- ///
- ///
- protected override void PreviewSend(IRequestInfo requestInfo)
- {
- throw new NotImplementedException();
- }
-
///
///
///
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/DelegateCollection.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/DelegateCollection.cs
index f95e06f7f..7741c9396 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/DelegateCollection.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/DelegateCollection.cs
@@ -22,67 +22,57 @@
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
-using System.Net;
-///
-/// 显示信息
-///
-///
-///
-public delegate void MessageEventHandler(TClient client, MsgPermitEventArgs e);
+namespace ThingsGateway.Foundation.Sockets
+{
+ ///
+ /// Connected
+ ///
+ ///
+ ///
+ ///
+ public delegate Task ConnectedEventHandler(TClient client, ConnectedEventArgs e);
-///
-/// 普通通知
-///
-///
-///
-///
-public delegate void TouchSocketEventHandler(TClient client, PluginEventArgs e);
+ ///
+ /// Connecting
+ ///
+ ///
+ ///
+ ///
+ public delegate Task ConnectingEventHandler(TClient client, ConnectingEventArgs e);
-///
-/// Id修改通知
-///
-///
-///
-///
-public delegate void IdChangedEventHandler(TClient client, IdChangedEventArgs e);
+ ///
+ /// 客户端断开连接
+ ///
+ ///
+ ///
+ ///
+ public delegate Task DisconnectEventHandler(TClient client, DisconnectEventArgs e);
-///
-/// Connecting
-///
-///
-///
-///
-public delegate void ConnectingEventHandler(TClient client, ConnectingEventArgs e);
+ ///
+ /// 显示信息
+ ///
+ ///
+ ///
+ public delegate void MessageEventHandler(TClient client, MsgPermitEventArgs e);
-///
-/// Connected
-///
-///
-///
-///
-public delegate void ConnectedEventHandler(TClient client, ConnectedEventArgs e);
+ ///
+ /// 接收数据
+ ///
+ ///
+ ///
+ public delegate Task ReceivedEventHandler(TClient client, ReceivedDataEventArgs e);
-///
-/// 客户端断开连接
-///
-///
-///
-///
-public delegate void DisconnectEventHandler(TClient client, DisconnectEventArgs e);
+ ///
+ /// 普通通知
+ ///
+ ///
+ ///
+ ///
+ public delegate void TouchSocketEventHandler(TClient client, PluginEventArgs e);
-///
-/// 接收数据
-///
-///
-///
-///
-public delegate void ReceivedEventHandler(TClient client, ByteBlock byteBlock, IRequestInfo requestInfo);
-
-///
-/// UDP接收
-///
-///
-///
-///
-public delegate void UdpReceivedEventHandler(EndPoint endpoint, ByteBlock byteBlock, IRequestInfo requestInfo);
\ No newline at end of file
+ ///
+ /// Udp接收
+ ///
+ public delegate Task UdpReceivedEventHandler(TClient client, UdpReceivedDataEventArgs e);
+}
\ No newline at end of file
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Enum/ReceiveType.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Enum/ReceiveType.cs
deleted file mode 100644
index 50d6b0118..000000000
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Enum/ReceiveType.cs
+++ /dev/null
@@ -1,48 +0,0 @@
-#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
-{
- ///
- /// 接收类型
- ///
- public enum ReceiveType : byte
- {
- ///
- /// 在该模式下,不会投递接收申请,用户可通过,获取到流以后,自己处理接收。
- /// 注意:连接端不会感知主动断开
- ///
- None,
-
- ///
- /// 该模式下会使用Iocp自动接收数据,然后主动触发。
- ///
- Iocp,
-
- ///
- /// 该模式下,会使用同步阻塞模式接收数据。注意:使用该模式时,每个回话连接会独占一个线程。
- ///
- Bio
- }
-}
\ No newline at end of file
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Extensions/ClientExtension.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Extensions/ClientExtension.cs
index d2ea23ccb..3e2214e12 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Extensions/ClientExtension.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Extensions/ClientExtension.cs
@@ -122,18 +122,39 @@ namespace ThingsGateway.Foundation.Sockets
///
public static TClient Connect(this TClient client, string ipHost, int timeout = 5000) where TClient : ITcpClient
{
- client.Setup(ipHost);
+ TouchSocketConfig config;
+ if (client.Config == null)
+ {
+ config = new TouchSocketConfig();
+ config.SetRemoteIPHost(ipHost);
+ client.Setup(config);
+ }
+ else
+ {
+ config = client.Config;
+ config.SetRemoteIPHost(ipHost);
+ }
client.Connect(timeout);
return client;
}
///
- public static Task ConnectAsync(this TClient client, string ipHost, int timeout = 5000) where TClient : ITcpClient
+ public static async Task ConnectAsync(this TClient client, string ipHost, int timeout = 5000) where TClient : ITcpClient
{
- return Task.Run(() =>
+ TouchSocketConfig config;
+ if (client.Config == null)
{
- return Connect(client, ipHost, timeout);
- });
+ config = new TouchSocketConfig();
+ config.SetRemoteIPHost(ipHost);
+ client.Setup(config);
+ }
+ else
+ {
+ config = client.Config;
+ config.SetRemoteIPHost(ipHost);
+ }
+ await client.ConnectAsync(timeout);
+ return client;
}
///
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Extensions/ServiceExtension.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Extensions/ServiceExtension.cs
index fb2a3a09e..967825079 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Extensions/ServiceExtension.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Extensions/ServiceExtension.cs
@@ -22,8 +22,18 @@ namespace ThingsGateway.Foundation.Sockets
///
public static TService Start(this TService service, params IPHost[] iPHosts) where TService : ITcpService
{
- service.Setup(new TouchSocketConfig()
- .SetListenIPHosts(iPHosts));
+ TouchSocketConfig config;
+ if (service.Config == null)
+ {
+ config = new TouchSocketConfig();
+ config.SetListenIPHosts(iPHosts);
+ service.Setup(config);
+ }
+ else
+ {
+ config = service.Config;
+ config.SetListenIPHosts(iPHosts);
+ }
service.Start();
return service;
}
@@ -35,8 +45,18 @@ namespace ThingsGateway.Foundation.Sockets
///
public static TService Start(this TService service, IPHost iPHost) where TService : IUdpSession
{
- service.Setup(new TouchSocketConfig()
- .SetBindIPHost(iPHost));
+ TouchSocketConfig config;
+ if (service.Config == null)
+ {
+ config = new TouchSocketConfig();
+ config.SetBindIPHost(iPHost);
+ service.Setup(config);
+ }
+ else
+ {
+ config = service.Config;
+ config.SetBindIPHost(iPHost);
+ }
service.Start();
return service;
}
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Extensions/TouchSocketConfigExtension.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Extensions/TouchSocketConfigExtension.cs
index fcc5b6a4f..de13c6369 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Extensions/TouchSocketConfigExtension.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Extensions/TouchSocketConfigExtension.cs
@@ -44,14 +44,6 @@ namespace ThingsGateway.Foundation.Sockets
///
public static readonly DependencyProperty> TcpDataHandlingAdapterProperty = DependencyProperty>.Register("TcpDataHandlingAdapter", () => { return new NormalDataHandlingAdapter(); });
- ///
- /// 接收类型,默认为
- /// 为自动接收数据,然后主动触发。
- /// 为不投递IO接收申请,用户可通过,获取到流以后,自己处理接收。注意:连接端不会感知主动断开
- /// 所需类型
- ///
- public static readonly DependencyProperty ReceiveTypeProperty = DependencyProperty.Register("ReceiveType", ReceiveType.Iocp);
-
///
/// 数据处理适配器,默认为获取
/// 所需类型
@@ -83,20 +75,6 @@ namespace ThingsGateway.Foundation.Sockets
return config;
}
- ///
- /// 接收类型,默认为
- /// 为自动接收数据,然后主动触发。
- /// 为不投递IO接收申请,用户可通过,获取到流以后,自己处理接收。注意:连接端不会感知主动断开
- ///
- ///
- ///
- ///
- public static TouchSocketConfig SetReceiveType(this TouchSocketConfig config, ReceiveType value)
- {
- config.SetValue(ReceiveTypeProperty, value);
- return config;
- }
-
///
/// 设置(Udp系)数据处理适配器。
///
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Interface/IClient.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Interface/IClient.cs
index 67851956c..6166898e7 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Interface/IClient.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Interface/IClient.cs
@@ -30,16 +30,16 @@ namespace ThingsGateway.Foundation.Sockets
///
public interface IClient : IDependencyObject, IDisposable, ISocket
{
+ ///
+ /// 获取一个同步数据接收器
+ ///
+ ///
+ IReceiver CreateReceiver();
///
- /// 处理未经过适配器的数据。返回值表示是否继续向下传递。
+ /// 移除同步数据接收器
///
- Func OnHandleRawBuffer { get; set; }
-
- ///
- /// 处理经过适配器后的数据。返回值表示是否继续向下传递。
- ///
- Func OnHandleReceivedData { get; set; }
+ void ClearReceiver();
///
/// 终端协议
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Interface/ISender/ISender.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Interface/ISender/ISender.cs
index 3942d4966..55533caa6 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Interface/ISender/ISender.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Interface/ISender/ISender.cs
@@ -22,7 +22,6 @@
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
-using System.Net.Sockets;
namespace ThingsGateway.Foundation.Sockets
{
@@ -46,8 +45,6 @@ namespace ThingsGateway.Foundation.Sockets
///
/// 异步发送数据。
- /// 在时,如果使用独立线程发送,则不会触发异常。
- /// 在时,相当于。
/// 该发送会经过适配器封装,具体封装内容由适配器决定。
///
/// 数据缓存区
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Interface/ITcpClient.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Interface/ITcpClient.cs
index c3a92c405..e91233ebc 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Interface/ITcpClient.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Interface/ITcpClient.cs
@@ -26,7 +26,7 @@
namespace ThingsGateway.Foundation.Sockets
{
///
- /// TCP客户端终端接口
+ /// Tcp客户端终端接口
///
public interface ITcpClient : ITcpClientBase, IClientSender, IPluginObject
{
@@ -65,12 +65,5 @@ namespace ThingsGateway.Foundation.Sockets
///
///
ITcpClient Setup(TouchSocketConfig config);
-
- ///
- /// 配置服务器
- ///
- ///
- ///
- ITcpClient Setup(string ipHost);
}
}
\ No newline at end of file
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Interface/ITcpClientBase.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Interface/ITcpClientBase.cs
index 48bca1866..5b924c053 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Interface/ITcpClientBase.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Interface/ITcpClientBase.cs
@@ -23,13 +23,12 @@
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
-using System.Net.Security;
using System.Net.Sockets;
namespace ThingsGateway.Foundation.Sockets
{
///
- /// TCP终端基础接口。
+ /// Tcp终端基础接口。
///
/// 注意:该接口并不仅表示客户端。也实现了该接口。
///
@@ -80,7 +79,7 @@ namespace ThingsGateway.Foundation.Sockets
///
/// 判断是否在线
- /// 该属性仅表示TCP状态是否在线
+ /// 该属性仅表示Tcp状态是否在线
///
bool Online { get; }
@@ -89,10 +88,7 @@ namespace ThingsGateway.Foundation.Sockets
///
int Port { get; }
- ///
- /// 接收模式
- ///
- public ReceiveType ReceiveType { get; }
+
///
/// 使用Ssl加密
@@ -106,11 +102,7 @@ namespace ThingsGateway.Foundation.Sockets
///
void Close(string msg = TouchSocketCoreUtility.Empty);
- ///
- /// 获取流,在正常模式下为,在Ssl模式下为。
- ///
- ///
- Stream GetStream();
+
///
/// 设置数据处理适配器
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Plugins/Interfaces/ITcpDisconnectingPlugin.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Plugins/Interfaces/ITcpDisconnectingPlugin.cs
index a4c8fa047..5fed661df 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Plugins/Interfaces/ITcpDisconnectingPlugin.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Plugins/Interfaces/ITcpDisconnectingPlugin.cs
@@ -19,9 +19,6 @@ namespace ThingsGateway.Foundation.Sockets
{
///
/// 即将断开连接(仅主动断开时有效)。
- ///
- /// 当主动调用Close断开时。
- ///
///
///
///
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/Plugins/Interfaces/IHttpPutPlugin.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Receiver/IReceiver.cs
similarity index 51%
rename from framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/Plugins/Interfaces/IHttpPutPlugin.cs
rename to framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Receiver/IReceiver.cs
index 96bfcf765..98902a5bd 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Http/Plugins/Interfaces/IHttpPutPlugin.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Receiver/IReceiver.cs
@@ -10,28 +10,27 @@
//------------------------------------------------------------------------------
#endregion
-namespace ThingsGateway.Foundation.Http
+namespace ThingsGateway.Foundation.Sockets
{
///
- /// IHttpPutPlugin
+ /// IReceiver
///
- [Obsolete("该插件已被弃用,请考虑使用“IHttpPlugin”插件代替使用。本插件将在正式版发布时直接移除。", true)]
- public interface IHttpPutPlugin : IPlugin where TClient : IHttpSocketClient
+ public interface IReceiver : IDisposable
{
///
- /// 在收到Put时
+ /// 异步等待并读取
///
- ///
- ///
+ ///
///
- Task OnHttpPut(TClient client, HttpContextEventArgs e);
- }
+ Task ReadAsync(CancellationToken token);
- ///
- /// IHttpPutPlugin
- ///
- [Obsolete("该插件已被弃用,请考虑使用“IHttpPlugin”插件代替使用。本插件将在正式版发布时直接移除。", true)]
- public interface IHttpPutPlugin : IHttpPutPlugin
- {
+#if NET6_0_OR_GREATER
+ ///
+ /// 值异步等待并读取
+ ///
+ ///
+ ///
+ public ValueTask ValueReadAsync(CancellationToken token);
+#endif
}
-}
\ No newline at end of file
+}
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Receiver/Receiver.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Receiver/Receiver.cs
new file mode 100644
index 000000000..6c8a746e7
--- /dev/null
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Receiver/Receiver.cs
@@ -0,0 +1,91 @@
+#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.Sockets
+{
+ ///
+ /// Receiver
+ ///
+ public class Receiver : DisposableObject, IReceiver
+ {
+ private readonly IClient m_client;
+ private readonly AutoResetEvent m_resetEventForComplateRead = new AutoResetEvent(false);
+ private readonly AsyncAutoResetEvent m_resetEventForRead = new AsyncAutoResetEvent(false);
+ private ByteBlock m_byteBlock;
+ private IRequestInfo m_requestInfo;
+
+ ///
+ /// Receiver
+ ///
+ ///
+ public Receiver(IClient client)
+ {
+ this.m_client = client;
+ }
+
+ ///
+ public async Task ReadAsync(CancellationToken token)
+ {
+ this.ThrowIfDisposed();
+ await this.m_resetEventForRead.WaitOneAsync(token);
+ return new ReceiverResult(this.ComplateRead, this.m_byteBlock, this.m_requestInfo);
+ }
+
+#if NET6_0_OR_GREATER
+ ///
+ public async ValueTask ValueReadAsync(CancellationToken token)
+ {
+ this.ThrowIfDisposed();
+ await this.m_resetEventForRead.WaitOneAsync(token);
+ return new ReceiverResult(this.ComplateRead, this.m_byteBlock, this.m_requestInfo);
+ }
+#endif
+
+ ///
+ public bool TryInputReceive(ByteBlock byteBlock, IRequestInfo requestInfo)
+ {
+ if (this.DisposedValue)
+ {
+ return false;
+ }
+ this.m_byteBlock = byteBlock;
+ this.m_requestInfo = requestInfo;
+ this.m_resetEventForRead.Set();
+ if (byteBlock == null && requestInfo == null)
+ {
+ return true;
+ }
+ if (this.m_resetEventForComplateRead.WaitOne(TimeSpan.FromSeconds(10)))
+ {
+ return true;
+ }
+ return false;
+ }
+
+ ///
+ protected override void Dispose(bool disposing)
+ {
+ this.m_client.ClearReceiver();
+ this.m_resetEventForComplateRead.SafeDispose();
+ this.m_resetEventForRead.SafeDispose();
+ this.m_byteBlock = null;
+ base.Dispose(disposing);
+ }
+
+ private void ComplateRead()
+ {
+ this.m_byteBlock = default;
+ this.m_requestInfo = default;
+ this.m_resetEventForComplateRead.Set();
+ }
+ }
+}
\ No newline at end of file
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Receiver/ReceiverResult.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Receiver/ReceiverResult.cs
new file mode 100644
index 000000000..bcd7bbb28
--- /dev/null
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/Receiver/ReceiverResult.cs
@@ -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
+
+namespace ThingsGateway.Foundation.Sockets
+{
+ ///
+ /// ReceiverResult
+ ///
+ public readonly struct ReceiverResult : IDisposable
+ {
+ private readonly Action m_disAction;
+
+ ///
+ /// SocketReceiveResult
+ ///
+ ///
+ ///
+ ///
+ public ReceiverResult(Action disAction, ByteBlock byteBlock, IRequestInfo requestInfo)
+ {
+ this.m_disAction = disAction;
+ this.ByteBlock = byteBlock;
+ this.RequestInfo = requestInfo;
+ }
+
+ ///
+ /// 字节块
+ ///
+ public ByteBlock ByteBlock { get; }
+
+ ///
+ /// 数据对象
+ ///
+ public IRequestInfo RequestInfo { get; }
+
+ ///
+ /// 连接已关闭
+ ///
+ public bool IsClosed => this.ByteBlock == null && this.RequestInfo == null;
+
+ ///
+ public void Dispose()
+ {
+ m_disAction?.Invoke();
+ }
+ }
+}
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/WaitingClient/IWaitingClient.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/WaitingClient/IWaitingClient.cs
index 942747584..839d1b982 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/WaitingClient/IWaitingClient.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/WaitingClient/IWaitingClient.cs
@@ -28,7 +28,7 @@ namespace ThingsGateway.Foundation.Sockets
///
/// 等待型客户端。
///
- public interface IWaitingClient : IWaitSender, IDisposable where TClient : IClient, IDefaultSender, ISender
+ public interface IWaitingClient : IWaitSender, IDisposable where TClient : IClient, ISender
{
///
/// 等待设置。
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/WaitingClient/ResponsedData.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/WaitingClient/ResponsedData.cs
index 931eed314..c4384319f 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/WaitingClient/ResponsedData.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/WaitingClient/ResponsedData.cs
@@ -30,18 +30,15 @@ namespace ThingsGateway.Foundation.Sockets
///
public struct ResponsedData
{
-
///
/// 构造函数
///
///
///
- ///
- public ResponsedData(byte[] data, IRequestInfo requestInfo, bool isRawBuffer)
+ public ResponsedData(byte[] data, IRequestInfo requestInfo)
{
this.Data = data;
this.RequestInfo = requestInfo;
- this.IsRawBuffer = isRawBuffer;
}
///
@@ -53,10 +50,5 @@ namespace ThingsGateway.Foundation.Sockets
/// RequestInfo
///
public IRequestInfo RequestInfo { get; private set; }
-
- ///
- /// 是否为原生缓存区。即没有经过适配器处理。
- ///
- public bool IsRawBuffer { get; private set; }
}
}
\ No newline at end of file
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/WaitingClient/WaitingClient.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/WaitingClient/WaitingClient.cs
index 34fa076a7..435d61010 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/WaitingClient/WaitingClient.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/WaitingClient/WaitingClient.cs
@@ -10,353 +10,279 @@
//------------------------------------------------------------------------------
#endregion
-namespace ThingsGateway.Foundation.Sockets;
+//------------------------------------------------------------------------------
+// 此代码版权(除特别声明或在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
+// 感谢您的下载和使用
+//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
-internal class WaitingClient : DisposableObject, IWaitingClient where TClient : IClient, IDefaultSender, ISender
+namespace ThingsGateway.Foundation.Sockets
{
- private readonly Func m_func;
- private readonly EasyLock easyLock = new();
- private readonly WaitData m_waitData = new();
- private readonly WaitDataAsync m_waitDataAsync = new();
-
- private volatile bool m_breaked;
-
- public WaitingClient(TClient client, WaitingOptions waitingOptions, Func func)
+ internal class WaitingClient : DisposableObject, IWaitingClient where TClient : IClient, ISender
{
- this.Client = client ?? throw new ArgumentNullException(nameof(client));
- this.WaitingOptions = waitingOptions;
- this.m_func = func;
- }
+ private readonly Func m_func;
+ private readonly SemaphoreSlim m_semaphoreSlim = new SemaphoreSlim(1, 1);
+ private volatile bool m_breaked;
+ private CancellationTokenSource m_cancellation;
- public WaitingClient(TClient client, WaitingOptions waitingOptions)
- {
- this.Client = client ?? throw new ArgumentNullException(nameof(client));
- this.WaitingOptions = waitingOptions;
- }
-
- public bool CanSend
- {
- get
+ public WaitingClient(TClient client, WaitingOptions waitingOptions, Func func)
{
- return this.Client is ITcpClientBase tcpClient ? tcpClient.CanSend : this.Client is IUdpSession;
- }
- }
-
- public TClient Client { get; private set; }
-
- public WaitingOptions WaitingOptions { get; set; }
-
- protected override void Dispose(bool disposing)
- {
- this.Client = default;
- this.m_waitData.SafeDispose();
- this.m_waitDataAsync.SafeDispose();
- base.Dispose(disposing);
- }
-
- private void Cancel()
- {
- this.m_waitData.Cancel();
- this.m_waitDataAsync.Cancel();
- }
-
- private void OnDisconnected(ITcpClientBase client, DisconnectEventArgs e)
- {
- this.m_breaked = true;
- this.Cancel();
- }
- private void OnSerialSessionDisconnected(ISerialSessionBase client, DisconnectEventArgs e)
- {
- this.m_breaked = true;
- this.Cancel();
- }
- private bool OnHandleRawBuffer(ByteBlock byteBlock)
- {
- var responsedData = new ResponsedData(byteBlock.ToArray(), null, true);
- if (this.m_func == null || this.m_func.Invoke(responsedData))
- {
- return !this.Set(responsedData);
- }
- else
- {
- return true;
- }
- }
-
- private bool OnHandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo)
- {
- ResponsedData responsedData;
- if (byteBlock != null)
- {
- responsedData = new ResponsedData(byteBlock.ToArray(), requestInfo, false);
- }
- else
- {
- responsedData = new ResponsedData(null, requestInfo, false);
+ this.Client = client ?? throw new ArgumentNullException(nameof(client));
+ this.WaitingOptions = waitingOptions;
+ this.m_func = func;
}
- if (this.m_func == null || this.m_func.Invoke(responsedData))
+ public WaitingClient(TClient client, WaitingOptions waitingOptions)
{
- return !this.Set(responsedData);
+ this.Client = client ?? throw new ArgumentNullException(nameof(client));
+ this.WaitingOptions = waitingOptions;
}
- else
+
+ public bool CanSend
{
- return true;
- }
- }
-
- private void Reset()
- {
- this.m_waitData.Reset();
- this.m_waitDataAsync.Reset();
- }
-
- #region 同步Response
-
- public ResponsedData SendThenResponse(byte[] buffer, int offset, int length, int timeout = 1000 * 5, CancellationToken cancellationToken = default)
- {
- try
- {
- easyLock.Wait();
- this.m_breaked = false;
- this.Reset();
- if (this.WaitingOptions.BreakTrigger && this.Client is ITcpClientBase tcpClient)
+ get
{
- tcpClient.Disconnected += this.OnDisconnected;
- }
- if (this.WaitingOptions.BreakTrigger && this.Client is ISerialSessionBase serialSession)
- {
- serialSession.Disconnected += this.OnSerialSessionDisconnected;
- }
- if (this.WaitingOptions.AdapterFilter == AdapterFilter.AllAdapter || this.WaitingOptions.AdapterFilter == AdapterFilter.WaitAdapter)
- {
- this.Client.OnHandleReceivedData += this.OnHandleReceivedData;
- }
- else
- {
- this.Client.OnHandleRawBuffer += this.OnHandleRawBuffer;
+ return this.Client is ITcpClientBase tcpClient ? tcpClient.CanSend : this.Client is ISerialSessionBase serialSession ? serialSession.CanSend : this.Client is IUdpSession;
}
+ }
- if (this.WaitingOptions.RemoteIPHost != null && this.Client is IUdpSession session)
+ public TClient Client { get; private set; }
+
+ public WaitingOptions WaitingOptions { get; set; }
+
+ protected override void Dispose(bool disposing)
+ {
+ this.Client = default;
+ this.Cancel();
+ base.Dispose(disposing);
+ }
+
+ private void Cancel()
+ {
+ this.m_cancellation.Cancel();
+ }
+
+ #region 同步Response
+
+ public ResponsedData SendThenResponse(byte[] buffer, int offset, int length, int timeout = 1000 * 5, CancellationToken token = default)
+ {
+ try
{
- if (this.WaitingOptions.AdapterFilter == AdapterFilter.AllAdapter || this.WaitingOptions.AdapterFilter == AdapterFilter.SendAdapter)
+ this.m_semaphoreSlim.Wait();
+ this.m_breaked = false;
+ if (token.CanBeCanceled)
{
- session.Send(this.WaitingOptions.RemoteIPHost.EndPoint, buffer, offset, length);
+ using CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(timeout);
+ m_cancellation = CancellationTokenSource.CreateLinkedTokenSource(cancellationTokenSource.Token, token);
}
else
{
- session.DefaultSend(this.WaitingOptions.RemoteIPHost.EndPoint, buffer, offset, length);
+ m_cancellation = new CancellationTokenSource(timeout);
}
- }
- else
- {
- if (this.WaitingOptions.AdapterFilter == AdapterFilter.AllAdapter || this.WaitingOptions.AdapterFilter == AdapterFilter.SendAdapter)
+ using (m_cancellation)
{
- this.Client.Send(buffer, offset, length);
- }
- else
- {
- this.Client.DefaultSend(buffer, offset, length);
- }
- }
-
- this.m_waitData.SetCancellationToken(cancellationToken);
- switch (this.m_waitData.Wait(timeout))
- {
- case WaitDataStatus.SetRunning:
- return this.m_waitData.WaitResult;
-
- case WaitDataStatus.Overtime:
- throw new TimeoutException();
- case WaitDataStatus.Canceled:
+ if (this.WaitingOptions.RemoteIPHost != null && this.Client is IUdpSession session)
{
- return this.WaitingOptions.ThrowBreakException && this.m_breaked ? throw new Exception("等待已终止。可能是客户端已掉线,或者被注销。") : (ResponsedData)default;
+ using (var receiver = session.CreateReceiver())
+ {
+ session.Send(this.WaitingOptions.RemoteIPHost.EndPoint, buffer, offset, length);
+
+ while (true)
+ {
+ using (var receiverResult = receiver.ReadAsync(m_cancellation.Token).GetFalseAwaitResult())
+ {
+ var response = new ResponsedData(receiverResult.ByteBlock?.ToArray(), receiverResult.RequestInfo);
+ }
+ }
+ }
}
- case WaitDataStatus.Default:
- case WaitDataStatus.Disposed:
- default:
- throw new Exception("未知错误");
- }
- }
- finally
- {
- easyLock.Release();
- if (this.WaitingOptions.BreakTrigger && this.Client is ITcpClientBase tcpClient)
- {
- tcpClient.Disconnected -= this.OnDisconnected;
- }
- if (this.WaitingOptions.BreakTrigger && this.Client is ISerialSessionBase serialSession)
- {
- serialSession.Disconnected -= this.OnSerialSessionDisconnected;
- }
- if (this.WaitingOptions.AdapterFilter == AdapterFilter.AllAdapter || this.WaitingOptions.AdapterFilter == AdapterFilter.WaitAdapter)
- {
- this.Client.OnHandleReceivedData -= this.OnHandleReceivedData;
- }
- else
- {
- this.Client.OnHandleRawBuffer -= this.OnHandleRawBuffer;
- }
- }
- }
-
-
-
- public ResponsedData SendThenResponse(byte[] buffer, int timeout = 1000 * 5, CancellationToken cancellationToken = default)
- {
- return this.SendThenResponse(buffer, 0, buffer.Length, timeout, cancellationToken);
- }
-
- public ResponsedData SendThenResponse(ByteBlock byteBlock, int timeout = 1000 * 5, CancellationToken cancellationToken = default)
- {
- return this.SendThenResponse(byteBlock.Buffer, 0, byteBlock.Len, timeout, cancellationToken);
- }
-
- #endregion 同步Response
-
- #region Response异步
-
- public async Task SendThenResponseAsync(byte[] buffer, int offset, int length, int timeout = 1000 * 5, CancellationToken cancellationToken = default)
- {
- try
- {
- await easyLock.WaitAsync();
- this.m_breaked = false;
- this.Reset();
- if (this.WaitingOptions.BreakTrigger && this.Client is ITcpClientBase tcpClient)
- {
- tcpClient.Disconnected += this.OnDisconnected;
- }
- if (this.WaitingOptions.BreakTrigger && this.Client is ISerialSessionBase serialSession)
- {
- serialSession.Disconnected += this.OnSerialSessionDisconnected;
- }
- if (this.WaitingOptions.AdapterFilter == AdapterFilter.AllAdapter || this.WaitingOptions.AdapterFilter == AdapterFilter.WaitAdapter)
- {
- this.Client.OnHandleReceivedData += this.OnHandleReceivedData;
- }
- else
- {
- this.Client.OnHandleRawBuffer += this.OnHandleRawBuffer;
- }
-
- if (this.WaitingOptions.RemoteIPHost != null && this.Client is IUdpSession session)
- {
- if (this.WaitingOptions.AdapterFilter == AdapterFilter.AllAdapter || this.WaitingOptions.AdapterFilter == AdapterFilter.SendAdapter)
- {
- session.Send(this.WaitingOptions.RemoteIPHost.EndPoint, buffer, offset, length);
- }
- else
- {
- session.DefaultSend(this.WaitingOptions.RemoteIPHost.EndPoint, buffer, offset, length);
- }
- }
- else
- {
- if (this.WaitingOptions.AdapterFilter == AdapterFilter.AllAdapter || this.WaitingOptions.AdapterFilter == AdapterFilter.SendAdapter)
- {
- this.Client.Send(buffer, offset, length);
- }
- else
- {
- this.Client.DefaultSend(buffer, offset, length);
- }
- }
-
- this.m_waitDataAsync.SetCancellationToken(cancellationToken);
- switch (await this.m_waitDataAsync.WaitAsync(timeout))
- {
- case WaitDataStatus.SetRunning:
- return this.m_waitData.WaitResult;
-
- case WaitDataStatus.Overtime:
- throw new TimeoutException();
- case WaitDataStatus.Canceled:
+ else
{
- return this.WaitingOptions.ThrowBreakException && this.m_breaked ? throw new Exception("等待已终止。可能是客户端已掉线,或者被注销。") : (ResponsedData)default;
+ using (var receiver = this.Client.CreateReceiver())
+ {
+ this.Client.Send(buffer, offset, length);
+ while (true)
+ {
+ using (var receiverResult = receiver.ReadAsync(m_cancellation.Token).GetFalseAwaitResult())
+ {
+ if (receiverResult.IsClosed)
+ {
+ this.m_breaked = true;
+ this.Cancel();
+ }
+ var response = new ResponsedData(receiverResult.ByteBlock?.ToArray(), receiverResult.RequestInfo);
+
+ if (this.m_func == null)
+ {
+ return response;
+ }
+ else
+ {
+ if (this.m_func.Invoke(response))
+ {
+ return response;
+ }
+ }
+ }
+ }
+ }
}
- case WaitDataStatus.Default:
- case WaitDataStatus.Disposed:
- default:
- throw new Exception("未知错误");
+ }
+ }
+ catch (OperationCanceledException)
+ {
+ return this.WaitingOptions.ThrowBreakException && this.m_breaked ? throw new Exception("等待已终止。可能是客户端已掉线,或者被注销。") : throw new TimeoutException();
+ }
+ finally
+ {
+ this.m_semaphoreSlim.Release();
}
}
- finally
+
+ public ResponsedData SendThenResponse(byte[] buffer, int timeout = 1000 * 5, CancellationToken token = default)
{
- easyLock.Release();
- if (this.WaitingOptions.BreakTrigger && this.Client is ITcpClientBase tcpClient)
+ return this.SendThenResponse(buffer, 0, buffer.Length, timeout, token);
+ }
+
+ public ResponsedData SendThenResponse(ByteBlock byteBlock, int timeout = 1000 * 5, CancellationToken token = default)
+ {
+ return this.SendThenResponse(byteBlock.Buffer, 0, byteBlock.Len, timeout, token);
+ }
+
+ #endregion 同步Response
+
+ #region Response异步
+
+ public async Task SendThenResponseAsync(byte[] buffer, int offset, int length, int timeout = 1000 * 5, CancellationToken token = default)
+ {
+ try
{
- tcpClient.Disconnected -= this.OnDisconnected;
+ await this.m_semaphoreSlim.WaitAsync();
+ this.m_breaked = false;
+ if (token.CanBeCanceled)
+ {
+ using CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(timeout);
+ m_cancellation = CancellationTokenSource.CreateLinkedTokenSource(cancellationTokenSource.Token, token);
+ }
+ else
+ {
+ m_cancellation = new CancellationTokenSource(timeout);
+ }
+ using (m_cancellation)
+ {
+ if (this.WaitingOptions.RemoteIPHost != null && this.Client is IUdpSession session)
+ {
+ using (var receiver = session.CreateReceiver())
+ {
+ await session.SendAsync(this.WaitingOptions.RemoteIPHost.EndPoint, buffer, offset, length);
+
+ while (true)
+ {
+ using (var receiverResult = await receiver.ReadAsync(m_cancellation.Token))
+ {
+ var response = new ResponsedData(receiverResult.ByteBlock?.ToArray(), receiverResult.RequestInfo);
+ }
+ }
+ }
+ }
+ else
+ {
+ using (var receiver = this.Client.CreateReceiver())
+ {
+ await this.Client.SendAsync(buffer, offset, length);
+ while (true)
+ {
+ using (var receiverResult = await receiver.ReadAsync(m_cancellation.Token))
+ {
+ if (receiverResult.IsClosed)
+ {
+ this.m_breaked = true;
+ this.Cancel();
+ }
+ var response = new ResponsedData(receiverResult.ByteBlock?.ToArray(), receiverResult.RequestInfo);
+
+ if (this.m_func == null)
+ {
+ return response;
+ }
+ else
+ {
+ if (this.m_func.Invoke(response))
+ {
+ return response;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
}
- if (this.WaitingOptions.BreakTrigger && this.Client is ISerialSessionBase serialSession)
+ catch (OperationCanceledException)
{
- serialSession.Disconnected -= this.OnSerialSessionDisconnected;
+ return this.WaitingOptions.ThrowBreakException && this.m_breaked ? throw new Exception("等待已终止。可能是客户端已掉线,或者被注销。") : throw new TimeoutException();
}
- if (this.WaitingOptions.AdapterFilter == AdapterFilter.AllAdapter || this.WaitingOptions.AdapterFilter == AdapterFilter.WaitAdapter)
+ finally
{
- this.Client.OnHandleReceivedData -= this.OnHandleReceivedData;
- }
- else
- {
- this.Client.OnHandleRawBuffer -= this.OnHandleRawBuffer;
+ this.m_semaphoreSlim.Release();
}
}
+
+ public Task SendThenResponseAsync(byte[] buffer, int timeout = 1000 * 5, CancellationToken token = default)
+ {
+ return this.SendThenResponseAsync(buffer, 0, buffer.Length, timeout, token);
+ }
+
+ public Task SendThenResponseAsync(ByteBlock byteBlock, int timeout = 1000 * 5, CancellationToken token = default)
+ {
+ return this.SendThenResponseAsync(byteBlock.Buffer, 0, byteBlock.Len, timeout, token);
+ }
+
+ #endregion Response异步
+
+ #region 字节同步
+
+ public byte[] SendThenReturn(byte[] buffer, int offset, int length, int timeout = 1000 * 5, CancellationToken token = default)
+ {
+ return this.SendThenResponse(buffer, offset, length, timeout, token).Data;
+ }
+
+ public byte[] SendThenReturn(byte[] buffer, int timeout = 1000 * 5, CancellationToken token = default)
+ {
+ return this.SendThenReturn(buffer, 0, buffer.Length, timeout, token);
+ }
+
+ public byte[] SendThenReturn(ByteBlock byteBlock, int timeout = 1000 * 5, CancellationToken token = default)
+ {
+ return this.SendThenReturn(byteBlock.Buffer, 0, byteBlock.Len, timeout, token);
+ }
+
+ #endregion 字节同步
+
+ #region 字节异步
+
+ public async Task SendThenReturnAsync(byte[] buffer, int offset, int length, int timeout = 1000 * 5, CancellationToken token = default)
+ {
+ return (await this.SendThenResponseAsync(buffer, offset, length, timeout, token)).Data;
+ }
+
+ public async Task SendThenReturnAsync(byte[] buffer, int timeout = 1000 * 5, CancellationToken token = default)
+ {
+ return (await this.SendThenResponseAsync(buffer, 0, buffer.Length, timeout, token)).Data;
+ }
+
+ public async Task SendThenReturnAsync(ByteBlock byteBlock, int timeout = 1000 * 5, CancellationToken token = default)
+ {
+ return (await this.SendThenResponseAsync(byteBlock.Buffer, 0, byteBlock.Len, timeout, token)).Data;
+ }
+
+ #endregion 字节异步
}
-
- public Task SendThenResponseAsync(byte[] buffer, int timeout = 1000 * 5, CancellationToken cancellationToken = default)
- {
- return this.SendThenResponseAsync(buffer, 0, buffer.Length, timeout, cancellationToken);
- }
-
- public Task SendThenResponseAsync(ByteBlock byteBlock, int timeout = 1000 * 5, CancellationToken cancellationToken = default)
- {
- return this.SendThenResponseAsync(byteBlock.Buffer, 0, byteBlock.Len, timeout, cancellationToken);
- }
-
- #endregion Response异步
-
- #region 字节同步
-
- public byte[] SendThenReturn(byte[] buffer, int offset, int length, int timeout = 1000 * 5, CancellationToken cancellationToken = default)
- {
- return this.SendThenResponse(buffer, offset, length, timeout, cancellationToken).Data;
- }
-
- public byte[] SendThenReturn(byte[] buffer, int timeout = 1000 * 5, CancellationToken cancellationToken = default)
- {
- return this.SendThenReturn(buffer, 0, buffer.Length, timeout, cancellationToken);
- }
-
- public byte[] SendThenReturn(ByteBlock byteBlock, int timeout = 1000 * 5, CancellationToken cancellationToken = default)
- {
- return this.SendThenReturn(byteBlock.Buffer, 0, byteBlock.Len, timeout, cancellationToken);
- }
-
- #endregion 字节同步
-
- #region 字节异步
-
- public async Task SendThenReturnAsync(byte[] buffer, int offset, int length, int timeout = 1000 * 5, CancellationToken cancellationToken = default)
- {
- return (await this.SendThenResponseAsync(buffer, offset, length, timeout, cancellationToken)).Data;
- }
-
- public async Task SendThenReturnAsync(byte[] buffer, int timeout = 1000 * 5, CancellationToken cancellationToken = default)
- {
- return (await this.SendThenResponseAsync(buffer, 0, buffer.Length, timeout, cancellationToken)).Data;
- }
-
- public async Task SendThenReturnAsync(ByteBlock byteBlock, int timeout = 1000 * 5, CancellationToken cancellationToken = default)
- {
- return (await this.SendThenResponseAsync(byteBlock.Buffer, 0, byteBlock.Len, timeout, cancellationToken)).Data;
- }
-
- #endregion 字节异步
-
- private bool Set(ResponsedData responsedData)
- {
- this.m_waitData.Set(responsedData);
- this.m_waitDataAsync.Set(responsedData);
- return true;
- }
-}
+}
\ No newline at end of file
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/WaitingClient/WaitingClientExtension.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/WaitingClient/WaitingClientExtension.cs
index 422e296af..af821c66f 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/WaitingClient/WaitingClientExtension.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/WaitingClient/WaitingClientExtension.cs
@@ -10,36 +10,49 @@
//------------------------------------------------------------------------------
#endregion
-namespace ThingsGateway.Foundation.Sockets;
+//------------------------------------------------------------------------------
+// 此代码版权(除特别声明或在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
+// 感谢您的下载和使用
+//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
-///
-/// WaitingClientExtensions
-///
-public static class WaitingClientExtension
+namespace ThingsGateway.Foundation.Sockets
{
///
- /// 获取筛选条件的可等待的客户端。
+ /// WaitingClientExtensions
///
- ///
- ///
- ///
- /// 当条件成立时返回
- ///
- public static IWaitingClient GetWaitingClientEx(this TClient client, WaitingOptions waitingOptions, Func func) where TClient : IClient, IDefaultSender, ISender
+ public static class WaitingClientExtension
{
- return new WaitingClient(client, waitingOptions, func);
- }
+ ///
+ /// 获取筛选条件的可等待的客户端。
+ ///
+ ///
+ ///
+ ///
+ /// 当条件成立时返回
+ ///
+ public static IWaitingClient GetWaitingClient(this TClient client, WaitingOptions waitingOptions, Func func) where TClient : IClient, ISender
+ {
+ return new WaitingClient(client, waitingOptions, func);
+ }
- ///
- /// 获取可等待的客户端。
- ///
- ///
- ///
- ///
- ///
- public static IWaitingClient GetWaitingClientEx(this TClient client, WaitingOptions waitingOptions) where TClient : IClient, IDefaultSender, ISender
- {
- var waitingClient = new WaitingClient(client, waitingOptions);
- return waitingClient;
+ ///
+ /// 获取可等待的客户端。
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static IWaitingClient GetWaitingClient(this TClient client, WaitingOptions waitingOptions) where TClient : IClient, ISender
+ {
+ return new WaitingClient(client, waitingOptions);
+ }
}
}
\ No newline at end of file
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/WaitingClient/WaitingOptions.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/WaitingClient/WaitingOptions.cs
index b483496a0..52147b988 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/WaitingClient/WaitingOptions.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Socket/WaitingClient/WaitingOptions.cs
@@ -25,41 +25,12 @@
namespace ThingsGateway.Foundation.Sockets
{
- ///
- /// 适配器筛选
- ///
- public enum AdapterFilter
- {
- ///
- /// 发送和接收都经过适配器
- ///
- AllAdapter,
-
- ///
- /// 发送经过适配器,接收不经过
- ///
- SendAdapter,
-
- ///
- /// 发送不经过适配器,接收经过
- ///
- WaitAdapter,
-
- ///
- /// 全都不经过适配器。
- ///
- NoneAll
- }
-
///
/// 等待设置
///
public class WaitingOptions
{
- ///
- /// 适配器筛选
- ///
- public AdapterFilter AdapterFilter { get; set; } = AdapterFilter.AllAdapter;
+
///
/// 当Client为Tcp系时。是否在断开连接时立即触发结果。默认会返回null。当为时,会触发异常。
///
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/DataAdapter/Decorators/AdapterData.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/Attributes/SwaggerDescriptionAttribute.cs
similarity index 61%
rename from framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/DataAdapter/Decorators/AdapterData.cs
rename to framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/Attributes/SwaggerDescriptionAttribute.cs
index 3f98b0f7e..674680bf4 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/DataAdapter/Decorators/AdapterData.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/Attributes/SwaggerDescriptionAttribute.cs
@@ -10,33 +10,33 @@
//------------------------------------------------------------------------------
#endregion
-namespace ThingsGateway.Foundation.Core
+namespace ThingsGateway.Foundation.WebApi.Swagger
{
///
- /// 适配器数据
+ /// Swagger描述特性
///
- public ref struct AdapterData
+ [AttributeUsage(AttributeTargets.Class)]
+ public sealed class SwaggerDescriptionAttribute : Attribute
{
///
- /// 适配器数据
+ /// Swagger描述特性
///
- ///
- ///
- public AdapterData(ByteBlock byteBlock, IRequestInfo requestInfo)
+ ///
+ public SwaggerDescriptionAttribute(params string[] groups)
{
- this.ByteBlock = byteBlock;
- this.RequestInfo = requestInfo;
+ this.Groups = groups;
}
///
- /// ByteBlock
+ /// Swagger描述特性
///
- public ByteBlock ByteBlock { get; private set; }
+ public SwaggerDescriptionAttribute()
+ {
+ }
///
- /// RequestInfo
+ /// 分组
///
- public IRequestInfo RequestInfo { get; private set; }
-
+ public string[] Groups { get; set; }
}
-}
+}
\ No newline at end of file
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/Common/OpenApiComponent.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/Common/OpenApiComponent.cs
new file mode 100644
index 000000000..2fc37027e
--- /dev/null
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/Common/OpenApiComponent.cs
@@ -0,0 +1,22 @@
+#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 Newtonsoft.Json;
+
+namespace ThingsGateway.Foundation.WebApi.Swagger
+{
+ internal class OpenApiComponent
+ {
+ [JsonProperty("schemas")]
+ public Dictionary Schemas { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/Common/OpenApiContent.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/Common/OpenApiContent.cs
new file mode 100644
index 000000000..43bfe2541
--- /dev/null
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/Common/OpenApiContent.cs
@@ -0,0 +1,22 @@
+#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 Newtonsoft.Json;
+
+namespace ThingsGateway.Foundation.WebApi.Swagger
+{
+ internal class OpenApiContent
+ {
+ [JsonProperty("schema")]
+ public OpenApiSchema Schema { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/Common/OpenApiDataTypes.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/Common/OpenApiDataTypes.cs
new file mode 100644
index 000000000..1b0f6330f
--- /dev/null
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/Common/OpenApiDataTypes.cs
@@ -0,0 +1,80 @@
+#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 Newtonsoft.Json;
+
+namespace ThingsGateway.Foundation.WebApi.Swagger
+{
+ [JsonConverter(typeof(OpenApiStringEnumConverter))]
+ internal enum OpenApiDataTypes
+ {
+ ///
+ /// 字符串
+ ///
+ String,
+
+ ///
+ /// 数值
+ ///
+ Number,
+
+ ///
+ /// 整数
+ ///
+ Integer,
+
+ ///
+ /// 布尔值
+ ///
+ Boolean,
+
+ ///
+ /// 二进制(如文件)
+ ///
+ Binary,
+
+ ///
+ /// 二进制集合
+ ///
+ BinaryCollection,
+
+ ///
+ /// 记录值(字典)
+ ///
+ Record,
+
+ ///
+ /// 元组值
+ ///
+ Tuple,
+
+ ///
+ /// 数组
+ ///
+ Array,
+
+ ///
+ /// 对象
+ ///
+ Object,
+
+ ///
+ /// 结构
+ ///
+ Struct,
+
+ ///
+ /// Any
+ ///
+ Any
+ }
+}
\ No newline at end of file
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/Common/OpenApiInfo.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/Common/OpenApiInfo.cs
new file mode 100644
index 000000000..3e94c7909
--- /dev/null
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/Common/OpenApiInfo.cs
@@ -0,0 +1,25 @@
+#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 Newtonsoft.Json;
+
+namespace ThingsGateway.Foundation.WebApi.Swagger
+{
+ internal class OpenApiInfo
+ {
+ [JsonProperty("title")]
+ public string Title { get; set; } = "API V1";
+
+ [JsonProperty("version")]
+ public string Version { get; set; } = "1.0";
+ }
+}
\ No newline at end of file
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/Common/OpenApiParameter.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/Common/OpenApiParameter.cs
new file mode 100644
index 000000000..05fbaae04
--- /dev/null
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/Common/OpenApiParameter.cs
@@ -0,0 +1,28 @@
+#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 Newtonsoft.Json;
+
+namespace ThingsGateway.Foundation.WebApi.Swagger
+{
+ internal class OpenApiParameter
+ {
+ [JsonProperty("name")]
+ public string Name { get; set; }
+
+ [JsonProperty("in")]
+ public string In { get; set; }
+
+ [JsonProperty("schema")]
+ public OpenApiSchema Schema { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/Common/OpenApiPath.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/Common/OpenApiPath.cs
new file mode 100644
index 000000000..3dde0aa78
--- /dev/null
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/Common/OpenApiPath.cs
@@ -0,0 +1,18 @@
+#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.WebApi.Swagger
+{
+ internal class OpenApiPath : Dictionary
+ {
+ }
+}
\ No newline at end of file
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/Common/OpenApiPathValue.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/Common/OpenApiPathValue.cs
new file mode 100644
index 000000000..fb090f94c
--- /dev/null
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/Common/OpenApiPathValue.cs
@@ -0,0 +1,40 @@
+#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 Newtonsoft.Json;
+
+namespace ThingsGateway.Foundation.WebApi.Swagger
+{
+ internal class OpenApiPathValue
+ {
+ [JsonProperty("tags")]
+ public IEnumerable Tags { get; set; }
+
+ [JsonProperty("summary")]
+ public string Summary { get; set; }
+
+ [JsonProperty("description")]
+ public string Description { get; set; }
+
+ [JsonProperty("operationId")]
+ public string OperationId { get; set; }
+
+ [JsonProperty("requestBody")]
+ public OpenApiRequestBody RequestBody { get; set; }
+
+ [JsonProperty("parameters")]
+ public IEnumerable Parameters { get; set; }
+
+ [JsonProperty("responses")]
+ public Dictionary Responses { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/Common/OpenApiProperty.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/Common/OpenApiProperty.cs
new file mode 100644
index 000000000..6f16266ed
--- /dev/null
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/Common/OpenApiProperty.cs
@@ -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
+
+using Newtonsoft.Json;
+
+namespace ThingsGateway.Foundation.WebApi.Swagger
+{
+ internal class OpenApiProperty
+ {
+ [JsonProperty("type")]
+ public OpenApiDataTypes? Type { get; set; }
+
+ [JsonProperty("readOnly")]
+ public bool? ReadOnly { get; set; }
+
+ [JsonProperty("$ref")]
+ public string Ref { get; set; }
+
+ [JsonProperty("format")]
+ public string Format { get; set; }
+
+ [JsonProperty("items")]
+ public OpenApiProperty Items { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/Common/OpenApiRequestBody.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/Common/OpenApiRequestBody.cs
new file mode 100644
index 000000000..83ae3c5d9
--- /dev/null
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/Common/OpenApiRequestBody.cs
@@ -0,0 +1,25 @@
+#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 Newtonsoft.Json;
+
+namespace ThingsGateway.Foundation.WebApi.Swagger
+{
+ internal class OpenApiRequestBody
+ {
+ [JsonProperty("description")]
+ public string Description { get; set; }
+
+ [JsonProperty("content")]
+ public Dictionary Content { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/Common/OpenApiResponse.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/Common/OpenApiResponse.cs
new file mode 100644
index 000000000..a164977dc
--- /dev/null
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/Common/OpenApiResponse.cs
@@ -0,0 +1,25 @@
+#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 Newtonsoft.Json;
+
+namespace ThingsGateway.Foundation.WebApi.Swagger
+{
+ internal class OpenApiResponse
+ {
+ [JsonProperty("description")]
+ public string Description { get; set; }
+
+ [JsonProperty("content")]
+ public Dictionary Content { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/Common/OpenApiRoot.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/Common/OpenApiRoot.cs
new file mode 100644
index 000000000..413b79a77
--- /dev/null
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/Common/OpenApiRoot.cs
@@ -0,0 +1,31 @@
+#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 Newtonsoft.Json;
+
+namespace ThingsGateway.Foundation.WebApi.Swagger
+{
+ internal class OpenApiRoot
+ {
+ [JsonProperty("openapi")]
+ public string OpenApi { get; set; } = "3.0.1";
+
+ [JsonProperty("info")]
+ public OpenApiInfo Info { get; set; }
+
+ [JsonProperty("paths")]
+ public Dictionary Paths { get; set; }
+
+ [JsonProperty("components")]
+ public OpenApiComponent Components { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/Common/OpenApiSchema.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/Common/OpenApiSchema.cs
new file mode 100644
index 000000000..1a54a51d7
--- /dev/null
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/Common/OpenApiSchema.cs
@@ -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
+
+using Newtonsoft.Json;
+
+namespace ThingsGateway.Foundation.WebApi.Swagger
+{
+ internal class OpenApiSchema
+ {
+ [JsonProperty("$ref")]
+ public string Ref { get; set; }
+
+ [JsonProperty("type")]
+ public OpenApiDataTypes? Type { get; set; }
+
+ [JsonProperty("format")]
+ public string Format { get; set; }
+
+ [JsonProperty("properties")]
+ public Dictionary Properties { get; set; }
+
+ [JsonProperty("items")]
+ public OpenApiSchema Items { get; set; }
+
+ [JsonProperty("enum")]
+ public int[] Enum { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/Extensions/OpenApiExtension.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/Extensions/OpenApiExtension.cs
new file mode 100644
index 000000000..c08232c42
--- /dev/null
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/Extensions/OpenApiExtension.cs
@@ -0,0 +1,40 @@
+#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.WebApi.Swagger
+{
+ internal static class OpenApiExtension
+ {
+ public static bool IsPrimitive(this OpenApiDataTypes dataTypes)
+ {
+ switch (dataTypes)
+ {
+ case OpenApiDataTypes.String:
+ case OpenApiDataTypes.Number:
+ case OpenApiDataTypes.Integer:
+ case OpenApiDataTypes.Boolean:
+ return true;
+
+ case OpenApiDataTypes.Binary:
+ case OpenApiDataTypes.BinaryCollection:
+ case OpenApiDataTypes.Record:
+ case OpenApiDataTypes.Tuple:
+ case OpenApiDataTypes.Array:
+ case OpenApiDataTypes.Object:
+ case OpenApiDataTypes.Struct:
+ case OpenApiDataTypes.Any:
+ default:
+ return false;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/DataAdapter/Decorators/SingleStreamDecorator.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/Extensions/SwaggerPluginsManagerExtension.cs
similarity index 58%
rename from framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/DataAdapter/Decorators/SingleStreamDecorator.cs
rename to framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/Extensions/SwaggerPluginsManagerExtension.cs
index 25b045de2..0143d6f29 100644
--- a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/Core/DataAdapter/Decorators/SingleStreamDecorator.cs
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/Extensions/SwaggerPluginsManagerExtension.cs
@@ -10,26 +10,21 @@
//------------------------------------------------------------------------------
#endregion
-namespace ThingsGateway.Foundation.Core
+namespace ThingsGateway.Foundation.WebApi.Swagger
{
///
- /// 单线程状况的流式数据处理适配器的装饰器。
+ /// SwaggerPluginsManagerExtension
///
- public class SingleStreamDecorator
+ public static class SwaggerPluginsManagerExtension
{
- private readonly SingleStreamDataHandlingAdapter m_adapter;
///
- /// 单线程状况的流式数据处理适配器的装饰器。
+ /// 使用插件。
///
- public SingleStreamDecorator(SingleStreamDataHandlingAdapter adapter)
+ ///
+ ///
+ public static SwaggerPlugin UseSwagger(this IPluginsManager pluginsManager)
{
- adapter.ReceivedCallBack = this.ReceivedCallBack;
- this.m_adapter = adapter;
- }
-
- private void ReceivedCallBack(ByteBlock block, IRequestInfo info)
- {
-
+ return pluginsManager.Add();
}
}
-}
+}
\ No newline at end of file
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/JsonConverters/OpenApiStringEnumConverter.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/JsonConverters/OpenApiStringEnumConverter.cs
new file mode 100644
index 000000000..4c384c11d
--- /dev/null
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/JsonConverters/OpenApiStringEnumConverter.cs
@@ -0,0 +1,24 @@
+#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 Newtonsoft.Json.Converters;
+using Newtonsoft.Json.Serialization;
+
+namespace ThingsGateway.Foundation.WebApi.Swagger
+{
+ internal class OpenApiStringEnumConverter : StringEnumConverter
+ {
+ public OpenApiStringEnumConverter() : base(new CamelCaseNamingStrategy())
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/Plugins/SwaggerPlugin.cs b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/Plugins/SwaggerPlugin.cs
new file mode 100644
index 000000000..9fefcbced
--- /dev/null
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/Plugins/SwaggerPlugin.cs
@@ -0,0 +1,701 @@
+#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 Newtonsoft.Json;
+
+using System.Collections;
+using System.Diagnostics;
+using System.Reflection;
+using System.Text;
+
+namespace ThingsGateway.Foundation.WebApi.Swagger
+{
+ ///
+ /// SwaggerPlugin
+ ///
+ public sealed class SwaggerPlugin : PluginBase, IServerStartedPlugin
+ {
+ private readonly IContainer m_container;
+ private readonly ILog m_logger;
+ private readonly Dictionary m_swagger = new Dictionary();
+
+ ///
+ /// SwaggerPlugin
+ ///
+ public SwaggerPlugin(IContainer container, ILog logger)
+ {
+ this.m_container = container;
+ this.m_logger = logger;
+ }
+
+ ///
+ /// 是否在浏览器打开Swagger页面
+ ///
+ public bool LaunchBrowser { get; set; }
+
+ ///
+ /// 访问Swagger的前缀,默认“swagger”
+ ///
+ public string Prefix { get; set; } = "swagger";
+
+ ///
+ public async Task OnServerStarted(IService sender, ServiceStateEventArgs e)
+ {
+ if (e.ServerState != ServerState.Running)
+ {
+ return;
+ }
+ if (!this.m_container.IsRegistered(typeof(WebApiParserPlugin)))
+ {
+ this.m_logger.Warning($"该服务器中似乎没有添加{nameof(WebApiParserPlugin)}插件(WebApi插件)。");
+ return;
+ }
+
+ var webApiParserPlugin = this.m_container.Resolve();
+ if (webApiParserPlugin == null)
+ {
+ return;
+ }
+
+ var assembly = Assembly.GetExecutingAssembly();
+ var names = assembly.GetManifestResourceNames();
+ foreach (var item in names)
+ {
+ using (var stream = assembly.GetManifestResourceStream(item))
+ {
+ var bytes = new byte[stream.Length];
+ stream.Read(bytes, 0, bytes.Length);
+ var prefix = this.Prefix.IsNullOrEmpty() ? "/" : (this.Prefix.StartsWith("/") ? this.Prefix : $"/{this.Prefix}");
+ var name = item.Replace("ThingsGateway.Foundation.WebApi.Swagger.api.", string.Empty);
+ if (name == "openapi.json")
+ {
+ try
+ {
+ bytes = this.BuildOpenApi(webApiParserPlugin);
+ }
+ catch (Exception ex)
+ {
+ this.m_logger.Exception(ex);
+ }
+ }
+ var key = prefix == "/" ? $"/{name}" : $"{prefix}/{name}";
+ this.m_swagger.Add(key, bytes);
+ }
+ }
+ await e.InvokeNext();
+
+ if (this.LaunchBrowser)
+ {
+ var iphost = (sender as ITcpService).Monitors.First().Option.IpHost;
+ string host;
+ if (iphost.IsLoopback || iphost.DnsSafeHost == "127.0.0.1" || iphost.DnsSafeHost == "0.0.0.0")
+ {
+ host = "127.0.0.1";
+ }
+ else
+ {
+ host = iphost.DnsSafeHost;
+ }
+
+ var scheme = iphost.Scheme == "https" ? iphost.Scheme : "http";
+
+ var prefix = this.Prefix.IsNullOrEmpty() ? "/" : (this.Prefix.StartsWith("/") ? this.Prefix : $"/{this.Prefix}");
+ var index = prefix == "/" ? $"/index.html" : $"{prefix}/index.html";
+ this.OpenWebLink($"{scheme}://{host}:{iphost.Port}{index}");
+ }
+ }
+
+ ///
+ /// 设置访问Swagger的前缀,默认“swagger”
+ ///
+ ///
+ ///
+ public SwaggerPlugin SetPrefix(string value)
+ {
+ this.Prefix = value;
+ return this;
+ }
+
+ ///
+ /// 在浏览器打开Swagger页面
+ ///
+ ///
+ public SwaggerPlugin UseLaunchBrowser()
+ {
+ this.LaunchBrowser = true;
+ return this;
+ }
+
+ ///
+ protected override void Loaded(IPluginsManager pluginsManager)
+ {
+ base.Loaded(pluginsManager);
+ pluginsManager.Add(nameof(IHttpPlugin.OnHttpRequest), this.OnHttpRequest);
+ }
+
+ ///
+ /// 检查类型是否是 IFormFileCollection 类型
+ ///
+ ///
+ ///
+ private static bool IsFormFileCollection(Type type)
+ {
+ // 如果是 MultifileCollection 类型则直接返回
+ if (typeof(MultifileCollection).IsAssignableFrom(type))
+ {
+ return true;
+ }
+
+ // 处理 IFormFile 集合类型
+ if (typeof(IEnumerable).IsAssignableFrom(type))
+ {
+ // 检查是否是 IFormFile 数组类型
+ if (type.IsArray)
+ {
+ // 获取数组元素类型
+ var elementType = type.GetElementType();
+
+ // 检查元素类型是否是 IFormFile 类型
+ if (elementType != null
+ && typeof(IFormFile).IsAssignableFrom(elementType))
+ {
+ return true;
+ }
+ }
+ // 检查是否是 IFormFile 集合类型
+ else
+ {
+ // 检查集合项类型是否是 IFormFile 类型
+ if (type.IsGenericType && type.GenericTypeArguments.Length == 1 && typeof(IFormFile).IsAssignableFrom(type.GenericTypeArguments[0]))
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ private void OpenWebLink(string url)
+ {
+ try
+ {
+ var psi = new ProcessStartInfo
+ {
+ FileName = url,
+ UseShellExecute = true
+ };
+ Process.Start(psi);
+ }
+ catch (Exception ex)
+ {
+ this.m_logger.Exception(ex);
+ }
+ }
+
+ #region Build
+
+ private void AddSchemaType(Type type, in List types)
+ {
+ if (type.IsArray)
+ {
+ type = type.GetElementType();
+ }
+ else if (typeof(IEnumerable).IsAssignableFrom(type) && type.IsGenericType && type.GenericTypeArguments.Length == 1)
+ {
+ type = type.GetGenericArguments()[0];
+ }
+
+ if (type.IsPrimitive || type == typeof(string))
+ {
+ return;
+ }
+
+ if (types.Contains(type))
+ {
+ return;
+ }
+ if (this.ParseDataTypes(type) != OpenApiDataTypes.Object)
+ {
+ return;
+ }
+ types.Add(type);
+
+ foreach (var item in type.GetProperties())
+ {
+ this.AddSchemaType(item.PropertyType, types);
+ }
+ }
+
+ private void BuildGet(WebApiParserPlugin webApiParserPlugin, in List schemaTypeList, in Dictionary paths)
+ {
+ foreach (var item in webApiParserPlugin.GetRouteMap)
+ {
+ //解析get
+ var methodInstance = item.Value;
+ var openApiPath = new OpenApiPath();
+
+ var openApiPathValue = new OpenApiPathValue
+ {
+ Tags = this.GetTags(methodInstance),
+ Description = methodInstance.GetDescription(),
+ Summary = methodInstance.GetDescription()
+ };
+ var i = 0;
+ if (methodInstance.MethodFlags.HasFlag(MethodFlags.IncludeCallContext))
+ {
+ i = 1;
+ }
+
+ var parameters = new List();
+ for (; i < methodInstance.Parameters.Length; i++)
+ {
+ var parameter = methodInstance.Parameters[i];
+ var openApiParameter = this.GetParameter(parameter);
+ openApiParameter.In = "query";
+
+ this.AddSchemaType(parameter.ParameterType, schemaTypeList);
+ parameters.Add(openApiParameter);
+ }
+
+ openApiPathValue.Parameters = parameters.Count > 0 ? parameters : null;
+
+ this.BuildResponse(methodInstance, openApiPathValue, schemaTypeList);
+
+ openApiPath.Add("get", openApiPathValue);
+ paths.Add(item.Key, openApiPath);
+ }
+ }
+
+ private byte[] BuildOpenApi(WebApiParserPlugin webApiParserPlugin)
+ {
+ var openApiRoot = new OpenApiRoot();
+ openApiRoot.Info = new OpenApiInfo();
+
+ var paths = new Dictionary();
+
+ var schemaTypeList = new List();
+
+ this.BuildGet(webApiParserPlugin, schemaTypeList, paths);
+ this.BuildPost(webApiParserPlugin, schemaTypeList, paths);
+
+ openApiRoot.Paths = paths;
+
+ openApiRoot.Components = this.GetComponents(schemaTypeList);
+
+ var jsonSetting = new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore };
+ return JsonConvert.SerializeObject(openApiRoot, Formatting.Indented, jsonSetting).ToUTF8Bytes();
+ }
+
+ private void BuildPost(WebApiParserPlugin webApiParserPlugin, in List schemaTypeList, in Dictionary paths)
+ {
+ foreach (var item in webApiParserPlugin.PostRouteMap)
+ {
+ //解析post
+ var methodInstance = item.Value;
+ var openApiPath = new OpenApiPath();
+
+ var openApiPathValue = new OpenApiPathValue
+ {
+ Tags = this.GetTags(methodInstance),
+ Description = methodInstance.GetDescription(),
+ Summary = methodInstance.GetDescription()
+ };
+
+ var i = 0;
+ if (methodInstance.MethodFlags.HasFlag(MethodFlags.IncludeCallContext))
+ {
+ i = 1;
+ }
+
+ var parameters = new List();
+ for (; i < methodInstance.Parameters.Length; i++)
+ {
+ var parameter = methodInstance.Parameters[i];
+ if (this.ParseDataTypes(parameter.ParameterType).IsPrimitive())
+ {
+ var openApiParameter = this.GetParameter(parameter);
+ openApiParameter.In = "query";
+ this.AddSchemaType(parameter.ParameterType, schemaTypeList);
+ parameters.Add(openApiParameter);
+ }
+ }
+
+ openApiPathValue.Parameters = parameters.Count > 0 ? parameters : default;
+
+ ParameterInfo parameterInfo = null;
+ if (methodInstance.MethodFlags.HasFlag(MethodFlags.IncludeCallContext))
+ {
+ if (methodInstance.Parameters.Length > 1)
+ {
+ parameterInfo = methodInstance.Parameters.Last();
+ }
+ }
+ else
+ {
+ if (methodInstance.Parameters.Length > 0)
+ {
+ parameterInfo = methodInstance.Parameters.Last();
+ }
+ }
+ if (parameterInfo != null && !this.ParseDataTypes(parameterInfo.ParameterType).IsPrimitive())
+ {
+ this.AddSchemaType(parameterInfo.ParameterType, schemaTypeList);
+
+ var body = new OpenApiRequestBody();
+ body.Content = new Dictionary();
+ var content = new OpenApiContent();
+ content.Schema = this.CreateSchema(parameterInfo.ParameterType);
+ body.Content.Add("application/json", content);
+ openApiPathValue.RequestBody = body;
+ }
+
+ this.BuildResponse(methodInstance, openApiPathValue, schemaTypeList);
+
+ openApiPath.Add("post", openApiPathValue);
+ paths.Add(item.Key, openApiPath);
+ }
+ }
+
+ private void BuildResponse(MethodInstance methodInstance, in OpenApiPathValue openApiPathValue, in List schemaTypeList)
+ {
+ var openApiResponse = new OpenApiResponse();
+ openApiResponse.Description = "Success";
+
+ if (methodInstance.HasReturn)
+ {
+ openApiResponse.Content = new Dictionary();
+ var openApiContent = new OpenApiContent();
+ openApiResponse.Content.Add("application/json", openApiContent);
+ openApiContent.Schema = this.CreateSchema(methodInstance.ReturnType);
+ this.AddSchemaType(methodInstance.ReturnType, schemaTypeList);
+ }
+
+ openApiPathValue.Responses = new Dictionary();
+ openApiPathValue.Responses.Add("200", openApiResponse);
+ }
+
+ private OpenApiProperty CreateProperty(Type type)
+ {
+ var openApiProperty = new OpenApiProperty();
+ var dataTypes = this.ParseDataTypes(type);
+
+ switch (dataTypes)
+ {
+ case OpenApiDataTypes.String:
+ case OpenApiDataTypes.Number:
+ case OpenApiDataTypes.Boolean:
+ case OpenApiDataTypes.Integer:
+ {
+ openApiProperty.Type = dataTypes;
+ break;
+ }
+ case OpenApiDataTypes.Binary:
+ break;
+
+ case OpenApiDataTypes.BinaryCollection:
+ break;
+
+ case OpenApiDataTypes.Record:
+ break;
+
+ case OpenApiDataTypes.Tuple:
+ break;
+
+ case OpenApiDataTypes.Array:
+ {
+ openApiProperty.Type = dataTypes;
+ openApiProperty.Items = this.CreateProperty(type.IsArray ? type.GetElementType() : type.GetGenericArguments()[0]);
+ }
+ break;
+
+ case OpenApiDataTypes.Object:
+ {
+ openApiProperty.Ref = $"#/components/schemas/{type.Name}";
+ break;
+ }
+ case OpenApiDataTypes.Struct:
+ break;
+
+ case OpenApiDataTypes.Any:
+ break;
+
+ default:
+ break;
+ }
+
+ openApiProperty.Format = this.GetSchemaFormat(type);
+
+ return openApiProperty;
+ }
+
+ private OpenApiSchema CreateSchema(Type type)
+ {
+ var schema = new OpenApiSchema();
+ var dataTypes = this.ParseDataTypes(type);
+
+ switch (dataTypes)
+ {
+ case OpenApiDataTypes.String:
+ case OpenApiDataTypes.Number:
+ case OpenApiDataTypes.Boolean:
+ case OpenApiDataTypes.Integer:
+ {
+ schema.Type = dataTypes;
+ break;
+ }
+ case OpenApiDataTypes.Binary:
+ break;
+
+ case OpenApiDataTypes.BinaryCollection:
+ break;
+
+ case OpenApiDataTypes.Record:
+ break;
+
+ case OpenApiDataTypes.Tuple:
+ break;
+
+ case OpenApiDataTypes.Array:
+ {
+ schema.Type = dataTypes;
+ schema.Items = this.CreateSchema(type.IsArray ? type.GetElementType() : type.GetGenericArguments()[0]);
+ }
+ break;
+
+ case OpenApiDataTypes.Object:
+ {
+ if (type.IsEnum)
+ {
+ schema.Enum = (int[])Enum.GetValues(type);
+ schema.Type = OpenApiDataTypes.Integer;
+ }
+ else
+ {
+ schema.Ref = $"#/components/schemas/{this.GetSchemaName(type)}";
+ }
+
+ break;
+ }
+ case OpenApiDataTypes.Struct:
+ break;
+
+ case OpenApiDataTypes.Any:
+ break;
+
+ default:
+ break;
+ }
+
+ schema.Format = this.GetSchemaFormat(type);
+ return schema;
+ }
+
+ private string GetSchemaName(Type type)
+ {
+ if (!type.IsGenericType)
+ {
+ return type.Name;
+ }
+
+ StringBuilder stringBuilder = new StringBuilder();
+ foreach (var item in type.GetGenericArguments())
+ {
+ stringBuilder.Append(GetSchemaName(item));
+ }
+ stringBuilder.Append(type.Name.Substring(0, type.Name.IndexOf('`')));
+ return stringBuilder.ToString();
+ }
+
+ private OpenApiComponent GetComponents(List types)
+ {
+ if (types.Count == 0)
+ {
+ return default;
+ }
+ var components = new OpenApiComponent();
+ components.Schemas = new Dictionary();
+ foreach (var type in types)
+ {
+ var schema = this.CreateSchema(type);
+ var properties = new Dictionary();
+ foreach (var propertyInfo in type.GetProperties(BindingFlags.Instance | BindingFlags.Public))
+ {
+ properties.Add(propertyInfo.Name, this.CreateProperty(propertyInfo.PropertyType));
+ }
+ schema.Properties = properties.Count == 0 ? default : properties;
+ components.Schemas.TryAdd(this.GetSchemaName(type), schema);
+ }
+ return components;
+ }
+
+ private string GetIn(Type type)
+ {
+ if (type.IsPrimitive || type == typeof(string))
+ {
+ return "query";
+ }
+
+ return null;
+ }
+
+ private OpenApiParameter GetParameter(ParameterInfo parameterInfo)
+ {
+ var openApiParameter = new OpenApiParameter();
+ openApiParameter.Name = parameterInfo.Name;
+
+ var openApiSchema = this.CreateSchema(parameterInfo.ParameterType);
+
+ openApiParameter.Schema = openApiSchema;
+
+ return openApiParameter;
+ }
+
+ private string GetSchemaFormat(Type type)
+ {
+ switch (Type.GetTypeCode(type))
+ {
+ case TypeCode.SByte:
+ case TypeCode.Byte:
+ case TypeCode.Int16:
+ case TypeCode.UInt16:
+ case TypeCode.Int32:
+ case TypeCode.UInt32:
+ return "int32";
+
+ case TypeCode.Int64:
+ case TypeCode.UInt64:
+ return "int64";
+
+ case TypeCode.Single:
+ return "float";
+
+ case TypeCode.Double:
+ case TypeCode.Decimal:
+ return "double";
+
+ case TypeCode.DateTime:
+ return "date-time";
+
+ case TypeCode.Boolean:
+ case TypeCode.Char:
+ case TypeCode.String:
+ return default;
+
+ default:
+ return "object";
+ }
+ }
+
+ private IEnumerable GetTags(MethodInstance methodInstance)
+ {
+ var tags = new List();
+ foreach (var item in methodInstance.ServerFromType.GetCustomAttributes(true))
+ {
+ if (item is SwaggerDescriptionAttribute descriptionAttribute)
+ {
+ if (descriptionAttribute.Groups != null)
+ {
+ tags.AddRange(descriptionAttribute.Groups);
+ }
+ }
+ }
+
+ foreach (var item in methodInstance.Info.GetCustomAttributes(true))
+ {
+ if (item is SwaggerDescriptionAttribute descriptionAttribute)
+ {
+ if (descriptionAttribute.Groups != null)
+ {
+ tags.AddRange(descriptionAttribute.Groups);
+ }
+ }
+ }
+
+ if (tags.Count == 0)
+ {
+ tags.Add(methodInstance.ServerFromType.Name);
+ }
+
+ return tags;
+ }
+
+ private Task OnHttpRequest(IHttpSocketClient client, HttpContextEventArgs e)
+ {
+ var context = e.Context;
+ var request = context.Request;
+ //var response = context.Response;
+
+ if (this.m_swagger.TryGetValue(request.RelativeURL, out var bytes))
+ {
+ e.Handled = true;
+ context.Response
+ .SetStatus()
+ .SetContentTypeByExtension(Path.GetExtension(request.RelativeURL))
+ .SetContent(bytes);
+ context.Response.Answer();
+ return EasyTask.CompletedTask;
+ }
+ return e.InvokeNext();
+ }
+
+ private OpenApiDataTypes ParseDataTypes(Type type)
+ {
+ // 空检查
+ if (type is null)
+ {
+ return OpenApiDataTypes.Any;
+ }
+
+ return type switch
+ {
+ // 字符串
+ _ when typeof(string).IsAssignableFrom(type)
+ || typeof(char).IsAssignableFrom(type) => OpenApiDataTypes.String,
+ // 整数
+ _ when type.IsInteger() => OpenApiDataTypes.Integer,
+
+ // 数值
+ _ when type.IsDecimal() => OpenApiDataTypes.Number,
+ // 布尔值
+ _ when typeof(bool).IsAssignableFrom(type) => OpenApiDataTypes.Boolean,
+ // 日期
+ _ when typeof(DateTime).IsAssignableFrom(type)
+ || typeof(DateTimeOffset).IsAssignableFrom(type) => OpenApiDataTypes.String,
+ // 二进制
+ _ when typeof(IFormFile).IsAssignableFrom(type) => OpenApiDataTypes.Binary,
+ // 二进制集合
+ _ when IsFormFileCollection(type) => OpenApiDataTypes.BinaryCollection,
+ // 记录值
+ _ when type.IsDictionary() => OpenApiDataTypes.Record,
+ // 元组值
+ _ when type.IsValueTuple() => OpenApiDataTypes.Tuple,
+ // 数组
+ _ when type.IsArray || (typeof(IEnumerable).IsAssignableFrom(type)
+ && type.IsGenericType
+ && type.GenericTypeArguments.Length == 1) => OpenApiDataTypes.Array,
+ // 对象
+ _ when type.IsEnum || (type != typeof(object)
+ && type.IsClass
+ && Type.GetTypeCode(type) == TypeCode.Object) => OpenApiDataTypes.Object,
+ // 结构
+ _ when type.IsValueType
+ && !type.IsPrimitive
+ && !type.IsEnum => OpenApiDataTypes.Struct,
+ // 缺省值
+ _ => OpenApiDataTypes.Any
+ };
+ }
+
+ #endregion Build
+ }
+}
\ No newline at end of file
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/api/favicon-16x16.png b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/api/favicon-16x16.png
new file mode 100644
index 0000000000000000000000000000000000000000..8b194e617af1c135e6b37939591d24ac3a5efa18
GIT binary patch
literal 665
zcmV;K0%rY*P)}JKSduyL>)s!A4EhTMMEM%Q;aL6%l#xiZiF>S;#Y{N2Zz%pvTGHJduXuC6Lx-)0EGfRy*N{Tv4i8@4oJ41gw
zKzThrcRe|7J~(YYIBq{SYCkn-KQm=N8$CrEK1CcqMI1dv9z#VRL_{D)L|`QmF8}}l
zJ9JV`Q}p!p_4f7m_U`WQ@apR4;o;!mnU<7}iG_qr
zF(e)x9~BG-3IzcG2M4an0002kNkl41`ZiN1i62V%{PM@Ry|IS_+Yc7{bb`MM~xm(7p4|kMHP&!VGuDW4kFixat
zXw43VmgwEvB$hXt_u=vZ>+v4i7E}n~eG6;n4Z=zF1n?T*yg<;W6kOfxpC6nao>VR%
z?fpr=asSJ&`L*wu^rLJ5Peq*PB0;alL#XazZCBxJLd&giTfw@!hW167F^`7kobi;(
ze<<>qNlP|xy7S1zl@lZNIBR7#o9ybJsptO#%}P0hz~sBp00000NkvXXu0mjfUsDF?
literal 0
HcmV?d00001
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/api/favicon-32x32.png b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/api/favicon-32x32.png
new file mode 100644
index 0000000000000000000000000000000000000000..249737fe44558e679f0b67134e274461d988fa98
GIT binary patch
literal 628
zcmV-)0*n2LP)Ma*GM0}OV<074bNCP7P7GVd{iMr*I6y~TMLss@FjvgL~HxU
z%Vvj33AwpD(Z4*$Mfx=HaU16axM
zt2xG_rloN<$iy9j9I5
+
+
+
+
+ Swagger UI
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/api/oauth2-redirect.html b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/api/oauth2-redirect.html
new file mode 100644
index 000000000..a427621e7
--- /dev/null
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/api/oauth2-redirect.html
@@ -0,0 +1,75 @@
+
+
+
+ Swagger UI: OAuth2 Redirect
+
+
+
+
+
\ No newline at end of file
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/api/openapi.json b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/api/openapi.json
new file mode 100644
index 000000000..07cc2e557
--- /dev/null
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/api/openapi.json
@@ -0,0 +1,78 @@
+{
+ "openapi": "3.0.1",
+ "info": {
+ "title": "API V1",
+ "version": "v1"
+ },
+ "paths": {
+ "/api/Todo": {
+ "get": {
+ "tags": [
+ "Todo"
+ ],
+ "operationId": "ApiTodoGet",
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "text/plain": {
+ "schema": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/ToDoItem"
+ }
+ }
+ },
+ "application/json": {
+ "schema": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/ToDoItem"
+ }
+ }
+ },
+ "text/json": {
+ "schema": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/ToDoItem"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/Todo/{id}": {
+ "get": {
+ "tags": [
+ "A"
+ ]
+ },
+ "put": {},
+ "delete": {}
+ }
+ },
+ "components": {
+ "schemas": {
+ "ToDoItem": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "integer",
+ "format": "int32"
+ },
+ "name": {
+ "type": "string",
+ "nullable": true
+ },
+ "isCompleted": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/api/swagger-ui-bundle.js b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/api/swagger-ui-bundle.js
new file mode 100644
index 000000000..3896e2b98
--- /dev/null
+++ b/framework/Foundation/ThingsGateway.Foundation/TouchSocket/WebApi.Swagger/api/swagger-ui-bundle.js
@@ -0,0 +1,3 @@
+/*! For license information please see swagger-ui-bundle.js.LICENSE.txt */
+!function (e, t) { "object" == typeof exports && "object" == typeof module ? module.exports = t(function () { try { return require("esprima") } catch (e) { } }()) : "function" == typeof define && define.amd ? define(["esprima"], t) : "object" == typeof exports ? exports.SwaggerUIBundle = t(function () { try { return require("esprima") } catch (e) { } }()) : e.SwaggerUIBundle = t(e.esprima) }(this, (function (e) { return function (e) { var t = {}; function n(r) { if (t[r]) return t[r].exports; var o = t[r] = { i: r, l: !1, exports: {} }; return e[r].call(o.exports, o, o.exports, n), o.l = !0, o.exports } return n.m = e, n.c = t, n.d = function (e, t, r) { n.o(e, t) || Object.defineProperty(e, t, { enumerable: !0, get: r }) }, n.r = function (e) { "undefined" != typeof Symbol && Symbol.toStringTag && Object.defineProperty(e, Symbol.toStringTag, { value: "Module" }), Object.defineProperty(e, "__esModule", { value: !0 }) }, n.t = function (e, t) { if (1 & t && (e = n(e)), 8 & t) return e; if (4 & t && "object" == typeof e && e && e.__esModule) return e; var r = Object.create(null); if (n.r(r), Object.defineProperty(r, "default", { enumerable: !0, value: e }), 2 & t && "string" != typeof e) for (var o in e) n.d(r, o, function (t) { return e[t] }.bind(null, o)); return r }, n.n = function (e) { var t = e && e.__esModule ? function () { return e.default } : function () { return e }; return n.d(t, "a", t), t }, n.o = function (e, t) { return Object.prototype.hasOwnProperty.call(e, t) }, n.p = "/dist", n(n.s = 549) }([function (e, t, n) { "use strict"; e.exports = n(129) }, function (e, t, n) { e.exports = function () { "use strict"; var e = Array.prototype.slice; function t(e, t) { t && (e.prototype = Object.create(t.prototype)), e.prototype.constructor = e } function n(e) { return i(e) ? e : $(e) } function r(e) { return s(e) ? e : K(e) } function o(e) { return u(e) ? e : Y(e) } function a(e) { return i(e) && !c(e) ? e : G(e) } function i(e) { return !(!e || !e[p]) } function s(e) { return !(!e || !e[f]) } function u(e) { return !(!e || !e[h]) } function c(e) { return s(e) || u(e) } function l(e) { return !(!e || !e[d]) } t(r, n), t(o, n), t(a, n), n.isIterable = i, n.isKeyed = s, n.isIndexed = u, n.isAssociative = c, n.isOrdered = l, n.Keyed = r, n.Indexed = o, n.Set = a; var p = "@@__IMMUTABLE_ITERABLE__@@", f = "@@__IMMUTABLE_KEYED__@@", h = "@@__IMMUTABLE_INDEXED__@@", d = "@@__IMMUTABLE_ORDERED__@@", m = "delete", v = 5, g = 1 << v, y = g - 1, b = {}, _ = { value: !1 }, w = { value: !1 }; function x(e) { return e.value = !1, e } function E(e) { e && (e.value = !0) } function S() { } function C(e, t) { t = t || 0; for (var n = Math.max(0, e.length - t), r = new Array(n), o = 0; o < n; o++)r[o] = e[o + t]; return r } function A(e) { return void 0 === e.size && (e.size = e.__iterate(O)), e.size } function k(e, t) { if ("number" != typeof t) { var n = t >>> 0; if ("" + n !== t || 4294967295 === n) return NaN; t = n } return t < 0 ? A(e) + t : t } function O() { return !0 } function j(e, t, n) { return (0 === e || void 0 !== n && e <= -n) && (void 0 === t || void 0 !== n && t >= n) } function T(e, t) { return P(e, t, 0) } function I(e, t) { return P(e, t, t) } function P(e, t, n) { return void 0 === e ? n : e < 0 ? Math.max(0, t + e) : void 0 === t ? e : Math.min(t, e) } var N = 0, M = 1, R = 2, D = "function" == typeof Symbol && Symbol.iterator, L = "@@iterator", B = D || L; function F(e) { this.next = e } function U(e, t, n, r) { var o = 0 === e ? t : 1 === e ? n : [t, n]; return r ? r.value = o : r = { value: o, done: !1 }, r } function q() { return { value: void 0, done: !0 } } function z(e) { return !!H(e) } function V(e) { return e && "function" == typeof e.next } function W(e) { var t = H(e); return t && t.call(e) } function H(e) { var t = e && (D && e[D] || e[L]); if ("function" == typeof t) return t } function J(e) { return e && "number" == typeof e.length } function $(e) { return null == e ? ie() : i(e) ? e.toSeq() : ce(e) } function K(e) { return null == e ? ie().toKeyedSeq() : i(e) ? s(e) ? e.toSeq() : e.fromEntrySeq() : se(e) } function Y(e) { return null == e ? ie() : i(e) ? s(e) ? e.entrySeq() : e.toIndexedSeq() : ue(e) } function G(e) { return (null == e ? ie() : i(e) ? s(e) ? e.entrySeq() : e : ue(e)).toSetSeq() } F.prototype.toString = function () { return "[Iterator]" }, F.KEYS = N, F.VALUES = M, F.ENTRIES = R, F.prototype.inspect = F.prototype.toSource = function () { return this.toString() }, F.prototype[B] = function () { return this }, t($, n), $.of = function () { return $(arguments) }, $.prototype.toSeq = function () { return this }, $.prototype.toString = function () { return this.__toString("Seq {", "}") }, $.prototype.cacheResult = function () { return !this._cache && this.__iterateUncached && (this._cache = this.entrySeq().toArray(), this.size = this._cache.length), this }, $.prototype.__iterate = function (e, t) { return pe(this, e, t, !0) }, $.prototype.__iterator = function (e, t) { return fe(this, e, t, !0) }, t(K, $), K.prototype.toKeyedSeq = function () { return this }, t(Y, $), Y.of = function () { return Y(arguments) }, Y.prototype.toIndexedSeq = function () { return this }, Y.prototype.toString = function () { return this.__toString("Seq [", "]") }, Y.prototype.__iterate = function (e, t) { return pe(this, e, t, !1) }, Y.prototype.__iterator = function (e, t) { return fe(this, e, t, !1) }, t(G, $), G.of = function () { return G(arguments) }, G.prototype.toSetSeq = function () { return this }, $.isSeq = ae, $.Keyed = K, $.Set = G, $.Indexed = Y; var Z, X, Q, ee = "@@__IMMUTABLE_SEQ__@@"; function te(e) { this._array = e, this.size = e.length } function ne(e) { var t = Object.keys(e); this._object = e, this._keys = t, this.size = t.length } function re(e) { this._iterable = e, this.size = e.length || e.size } function oe(e) { this._iterator = e, this._iteratorCache = [] } function ae(e) { return !(!e || !e[ee]) } function ie() { return Z || (Z = new te([])) } function se(e) { var t = Array.isArray(e) ? new te(e).fromEntrySeq() : V(e) ? new oe(e).fromEntrySeq() : z(e) ? new re(e).fromEntrySeq() : "object" == typeof e ? new ne(e) : void 0; if (!t) throw new TypeError("Expected Array or iterable object of [k, v] entries, or keyed object: " + e); return t } function ue(e) { var t = le(e); if (!t) throw new TypeError("Expected Array or iterable object of values: " + e); return t } function ce(e) { var t = le(e) || "object" == typeof e && new ne(e); if (!t) throw new TypeError("Expected Array or iterable object of values, or keyed object: " + e); return t } function le(e) { return J(e) ? new te(e) : V(e) ? new oe(e) : z(e) ? new re(e) : void 0 } function pe(e, t, n, r) { var o = e._cache; if (o) { for (var a = o.length - 1, i = 0; i <= a; i++) { var s = o[n ? a - i : i]; if (!1 === t(s[1], r ? s[0] : i, e)) return i + 1 } return i } return e.__iterateUncached(t, n) } function fe(e, t, n, r) { var o = e._cache; if (o) { var a = o.length - 1, i = 0; return new F((function () { var e = o[n ? a - i : i]; return i++ > a ? q() : U(t, r ? e[0] : i - 1, e[1]) })) } return e.__iteratorUncached(t, n) } function he(e, t) { return t ? de(t, e, "", { "": e }) : me(e) } function de(e, t, n, r) { return Array.isArray(t) ? e.call(r, n, Y(t).map((function (n, r) { return de(e, n, r, t) }))) : ve(t) ? e.call(r, n, K(t).map((function (n, r) { return de(e, n, r, t) }))) : t } function me(e) { return Array.isArray(e) ? Y(e).map(me).toList() : ve(e) ? K(e).map(me).toMap() : e } function ve(e) { return e && (e.constructor === Object || void 0 === e.constructor) } function ge(e, t) { if (e === t || e != e && t != t) return !0; if (!e || !t) return !1; if ("function" == typeof e.valueOf && "function" == typeof t.valueOf) { if ((e = e.valueOf()) === (t = t.valueOf()) || e != e && t != t) return !0; if (!e || !t) return !1 } return !("function" != typeof e.equals || "function" != typeof t.equals || !e.equals(t)) } function ye(e, t) { if (e === t) return !0; if (!i(t) || void 0 !== e.size && void 0 !== t.size && e.size !== t.size || void 0 !== e.__hash && void 0 !== t.__hash && e.__hash !== t.__hash || s(e) !== s(t) || u(e) !== u(t) || l(e) !== l(t)) return !1; if (0 === e.size && 0 === t.size) return !0; var n = !c(e); if (l(e)) { var r = e.entries(); return t.every((function (e, t) { var o = r.next().value; return o && ge(o[1], e) && (n || ge(o[0], t)) })) && r.next().done } var o = !1; if (void 0 === e.size) if (void 0 === t.size) "function" == typeof e.cacheResult && e.cacheResult(); else { o = !0; var a = e; e = t, t = a } var p = !0, f = t.__iterate((function (t, r) { if (n ? !e.has(t) : o ? !ge(t, e.get(r, b)) : !ge(e.get(r, b), t)) return p = !1, !1 })); return p && e.size === f } function be(e, t) { if (!(this instanceof be)) return new be(e, t); if (this._value = e, this.size = void 0 === t ? 1 / 0 : Math.max(0, t), 0 === this.size) { if (X) return X; X = this } } function _e(e, t) { if (!e) throw new Error(t) } function we(e, t, n) { if (!(this instanceof we)) return new we(e, t, n); if (_e(0 !== n, "Cannot step a Range by 0"), e = e || 0, void 0 === t && (t = 1 / 0), n = void 0 === n ? 1 : Math.abs(n), t < e && (n = -n), this._start = e, this._end = t, this._step = n, this.size = Math.max(0, Math.ceil((t - e) / n - 1) + 1), 0 === this.size) { if (Q) return Q; Q = this } } function xe() { throw TypeError("Abstract") } function Ee() { } function Se() { } function Ce() { } $.prototype[ee] = !0, t(te, Y), te.prototype.get = function (e, t) { return this.has(e) ? this._array[k(this, e)] : t }, te.prototype.__iterate = function (e, t) { for (var n = this._array, r = n.length - 1, o = 0; o <= r; o++)if (!1 === e(n[t ? r - o : o], o, this)) return o + 1; return o }, te.prototype.__iterator = function (e, t) { var n = this._array, r = n.length - 1, o = 0; return new F((function () { return o > r ? q() : U(e, o, n[t ? r - o++ : o++]) })) }, t(ne, K), ne.prototype.get = function (e, t) { return void 0 === t || this.has(e) ? this._object[e] : t }, ne.prototype.has = function (e) { return this._object.hasOwnProperty(e) }, ne.prototype.__iterate = function (e, t) { for (var n = this._object, r = this._keys, o = r.length - 1, a = 0; a <= o; a++) { var i = r[t ? o - a : a]; if (!1 === e(n[i], i, this)) return a + 1 } return a }, ne.prototype.__iterator = function (e, t) { var n = this._object, r = this._keys, o = r.length - 1, a = 0; return new F((function () { var i = r[t ? o - a : a]; return a++ > o ? q() : U(e, i, n[i]) })) }, ne.prototype[d] = !0, t(re, Y), re.prototype.__iterateUncached = function (e, t) { if (t) return this.cacheResult().__iterate(e, t); var n = W(this._iterable), r = 0; if (V(n)) for (var o; !(o = n.next()).done && !1 !== e(o.value, r++, this);); return r }, re.prototype.__iteratorUncached = function (e, t) { if (t) return this.cacheResult().__iterator(e, t); var n = W(this._iterable); if (!V(n)) return new F(q); var r = 0; return new F((function () { var t = n.next(); return t.done ? t : U(e, r++, t.value) })) }, t(oe, Y), oe.prototype.__iterateUncached = function (e, t) { if (t) return this.cacheResult().__iterate(e, t); for (var n, r = this._iterator, o = this._iteratorCache, a = 0; a < o.length;)if (!1 === e(o[a], a++, this)) return a; for (; !(n = r.next()).done;) { var i = n.value; if (o[a] = i, !1 === e(i, a++, this)) break } return a }, oe.prototype.__iteratorUncached = function (e, t) { if (t) return this.cacheResult().__iterator(e, t); var n = this._iterator, r = this._iteratorCache, o = 0; return new F((function () { if (o >= r.length) { var t = n.next(); if (t.done) return t; r[o] = t.value } return U(e, o, r[o++]) })) }, t(be, Y), be.prototype.toString = function () { return 0 === this.size ? "Repeat []" : "Repeat [ " + this._value + " " + this.size + " times ]" }, be.prototype.get = function (e, t) { return this.has(e) ? this._value : t }, be.prototype.includes = function (e) { return ge(this._value, e) }, be.prototype.slice = function (e, t) { var n = this.size; return j(e, t, n) ? this : new be(this._value, I(t, n) - T(e, n)) }, be.prototype.reverse = function () { return this }, be.prototype.indexOf = function (e) { return ge(this._value, e) ? 0 : -1 }, be.prototype.lastIndexOf = function (e) { return ge(this._value, e) ? this.size : -1 }, be.prototype.__iterate = function (e, t) { for (var n = 0; n < this.size; n++)if (!1 === e(this._value, n, this)) return n + 1; return n }, be.prototype.__iterator = function (e, t) { var n = this, r = 0; return new F((function () { return r < n.size ? U(e, r++, n._value) : q() })) }, be.prototype.equals = function (e) { return e instanceof be ? ge(this._value, e._value) : ye(e) }, t(we, Y), we.prototype.toString = function () { return 0 === this.size ? "Range []" : "Range [ " + this._start + "..." + this._end + (1 !== this._step ? " by " + this._step : "") + " ]" }, we.prototype.get = function (e, t) { return this.has(e) ? this._start + k(this, e) * this._step : t }, we.prototype.includes = function (e) { var t = (e - this._start) / this._step; return t >= 0 && t < this.size && t === Math.floor(t) }, we.prototype.slice = function (e, t) { return j(e, t, this.size) ? this : (e = T(e, this.size), (t = I(t, this.size)) <= e ? new we(0, 0) : new we(this.get(e, this._end), this.get(t, this._end), this._step)) }, we.prototype.indexOf = function (e) { var t = e - this._start; if (t % this._step == 0) { var n = t / this._step; if (n >= 0 && n < this.size) return n } return -1 }, we.prototype.lastIndexOf = function (e) { return this.indexOf(e) }, we.prototype.__iterate = function (e, t) { for (var n = this.size - 1, r = this._step, o = t ? this._start + n * r : this._start, a = 0; a <= n; a++) { if (!1 === e(o, a, this)) return a + 1; o += t ? -r : r } return a }, we.prototype.__iterator = function (e, t) { var n = this.size - 1, r = this._step, o = t ? this._start + n * r : this._start, a = 0; return new F((function () { var i = o; return o += t ? -r : r, a > n ? q() : U(e, a++, i) })) }, we.prototype.equals = function (e) { return e instanceof we ? this._start === e._start && this._end === e._end && this._step === e._step : ye(this, e) }, t(xe, n), t(Ee, xe), t(Se, xe), t(Ce, xe), xe.Keyed = Ee, xe.Indexed = Se, xe.Set = Ce; var Ae = "function" == typeof Math.imul && -2 === Math.imul(4294967295, 2) ? Math.imul : function (e, t) { var n = 65535 & (e |= 0), r = 65535 & (t |= 0); return n * r + ((e >>> 16) * r + n * (t >>> 16) << 16 >>> 0) | 0 }; function ke(e) { return e >>> 1 & 1073741824 | 3221225471 & e } function Oe(e) { if (!1 === e || null == e) return 0; if ("function" == typeof e.valueOf && (!1 === (e = e.valueOf()) || null == e)) return 0; if (!0 === e) return 1; var t = typeof e; if ("number" === t) { if (e != e || e === 1 / 0) return 0; var n = 0 | e; for (n !== e && (n ^= 4294967295 * e); e > 4294967295;)n ^= e /= 4294967295; return ke(n) } if ("string" === t) return e.length > Fe ? je(e) : Te(e); if ("function" == typeof e.hashCode) return e.hashCode(); if ("object" === t) return Ie(e); if ("function" == typeof e.toString) return Te(e.toString()); throw new Error("Value type " + t + " cannot be hashed.") } function je(e) { var t = ze[e]; return void 0 === t && (t = Te(e), qe === Ue && (qe = 0, ze = {}), qe++, ze[e] = t), t } function Te(e) { for (var t = 0, n = 0; n < e.length; n++)t = 31 * t + e.charCodeAt(n) | 0; return ke(t) } function Ie(e) { var t; if (De && void 0 !== (t = Re.get(e))) return t; if (void 0 !== (t = e[Be])) return t; if (!Ne) { if (void 0 !== (t = e.propertyIsEnumerable && e.propertyIsEnumerable[Be])) return t; if (void 0 !== (t = Me(e))) return t } if (t = ++Le, 1073741824 & Le && (Le = 0), De) Re.set(e, t); else { if (void 0 !== Pe && !1 === Pe(e)) throw new Error("Non-extensible objects are not allowed as keys."); if (Ne) Object.defineProperty(e, Be, { enumerable: !1, configurable: !1, writable: !1, value: t }); else if (void 0 !== e.propertyIsEnumerable && e.propertyIsEnumerable === e.constructor.prototype.propertyIsEnumerable) e.propertyIsEnumerable = function () { return this.constructor.prototype.propertyIsEnumerable.apply(this, arguments) }, e.propertyIsEnumerable[Be] = t; else { if (void 0 === e.nodeType) throw new Error("Unable to set a non-enumerable property on object."); e[Be] = t } } return t } var Pe = Object.isExtensible, Ne = function () { try { return Object.defineProperty({}, "@", {}), !0 } catch (e) { return !1 } }(); function Me(e) { if (e && e.nodeType > 0) switch (e.nodeType) { case 1: return e.uniqueID; case 9: return e.documentElement && e.documentElement.uniqueID } } var Re, De = "function" == typeof WeakMap; De && (Re = new WeakMap); var Le = 0, Be = "__immutablehash__"; "function" == typeof Symbol && (Be = Symbol(Be)); var Fe = 16, Ue = 255, qe = 0, ze = {}; function Ve(e) { _e(e !== 1 / 0, "Cannot perform this action with an infinite size.") } function We(e) { return null == e ? ot() : He(e) && !l(e) ? e : ot().withMutations((function (t) { var n = r(e); Ve(n.size), n.forEach((function (e, n) { return t.set(n, e) })) })) } function He(e) { return !(!e || !e[$e]) } t(We, Ee), We.of = function () { var t = e.call(arguments, 0); return ot().withMutations((function (e) { for (var n = 0; n < t.length; n += 2) { if (n + 1 >= t.length) throw new Error("Missing value for key: " + t[n]); e.set(t[n], t[n + 1]) } })) }, We.prototype.toString = function () { return this.__toString("Map {", "}") }, We.prototype.get = function (e, t) { return this._root ? this._root.get(0, void 0, e, t) : t }, We.prototype.set = function (e, t) { return at(this, e, t) }, We.prototype.setIn = function (e, t) { return this.updateIn(e, b, (function () { return t })) }, We.prototype.remove = function (e) { return at(this, e, b) }, We.prototype.deleteIn = function (e) { return this.updateIn(e, (function () { return b })) }, We.prototype.update = function (e, t, n) { return 1 === arguments.length ? e(this) : this.updateIn([e], t, n) }, We.prototype.updateIn = function (e, t, n) { n || (n = t, t = void 0); var r = vt(this, xn(e), t, n); return r === b ? void 0 : r }, We.prototype.clear = function () { return 0 === this.size ? this : this.__ownerID ? (this.size = 0, this._root = null, this.__hash = void 0, this.__altered = !0, this) : ot() }, We.prototype.merge = function () { return ft(this, void 0, arguments) }, We.prototype.mergeWith = function (t) { return ft(this, t, e.call(arguments, 1)) }, We.prototype.mergeIn = function (t) { var n = e.call(arguments, 1); return this.updateIn(t, ot(), (function (e) { return "function" == typeof e.merge ? e.merge.apply(e, n) : n[n.length - 1] })) }, We.prototype.mergeDeep = function () { return ft(this, ht, arguments) }, We.prototype.mergeDeepWith = function (t) { var n = e.call(arguments, 1); return ft(this, dt(t), n) }, We.prototype.mergeDeepIn = function (t) { var n = e.call(arguments, 1); return this.updateIn(t, ot(), (function (e) { return "function" == typeof e.mergeDeep ? e.mergeDeep.apply(e, n) : n[n.length - 1] })) }, We.prototype.sort = function (e) { return zt(pn(this, e)) }, We.prototype.sortBy = function (e, t) { return zt(pn(this, t, e)) }, We.prototype.withMutations = function (e) { var t = this.asMutable(); return e(t), t.wasAltered() ? t.__ensureOwner(this.__ownerID) : this }, We.prototype.asMutable = function () { return this.__ownerID ? this : this.__ensureOwner(new S) }, We.prototype.asImmutable = function () { return this.__ensureOwner() }, We.prototype.wasAltered = function () { return this.__altered }, We.prototype.__iterator = function (e, t) { return new et(this, e, t) }, We.prototype.__iterate = function (e, t) { var n = this, r = 0; return this._root && this._root.iterate((function (t) { return r++, e(t[1], t[0], n) }), t), r }, We.prototype.__ensureOwner = function (e) { return e === this.__ownerID ? this : e ? rt(this.size, this._root, e, this.__hash) : (this.__ownerID = e, this.__altered = !1, this) }, We.isMap = He; var Je, $e = "@@__IMMUTABLE_MAP__@@", Ke = We.prototype; function Ye(e, t) { this.ownerID = e, this.entries = t } function Ge(e, t, n) { this.ownerID = e, this.bitmap = t, this.nodes = n } function Ze(e, t, n) { this.ownerID = e, this.count = t, this.nodes = n } function Xe(e, t, n) { this.ownerID = e, this.keyHash = t, this.entries = n } function Qe(e, t, n) { this.ownerID = e, this.keyHash = t, this.entry = n } function et(e, t, n) { this._type = t, this._reverse = n, this._stack = e._root && nt(e._root) } function tt(e, t) { return U(e, t[0], t[1]) } function nt(e, t) { return { node: e, index: 0, __prev: t } } function rt(e, t, n, r) { var o = Object.create(Ke); return o.size = e, o._root = t, o.__ownerID = n, o.__hash = r, o.__altered = !1, o } function ot() { return Je || (Je = rt(0)) } function at(e, t, n) { var r, o; if (e._root) { var a = x(_), i = x(w); if (r = it(e._root, e.__ownerID, 0, void 0, t, n, a, i), !i.value) return e; o = e.size + (a.value ? n === b ? -1 : 1 : 0) } else { if (n === b) return e; o = 1, r = new Ye(e.__ownerID, [[t, n]]) } return e.__ownerID ? (e.size = o, e._root = r, e.__hash = void 0, e.__altered = !0, e) : r ? rt(o, r) : ot() } function it(e, t, n, r, o, a, i, s) { return e ? e.update(t, n, r, o, a, i, s) : a === b ? e : (E(s), E(i), new Qe(t, r, [o, a])) } function st(e) { return e.constructor === Qe || e.constructor === Xe } function ut(e, t, n, r, o) { if (e.keyHash === r) return new Xe(t, r, [e.entry, o]); var a, i = (0 === n ? e.keyHash : e.keyHash >>> n) & y, s = (0 === n ? r : r >>> n) & y; return new Ge(t, 1 << i | 1 << s, i === s ? [ut(e, t, n + v, r, o)] : (a = new Qe(t, r, o), i < s ? [e, a] : [a, e])) } function ct(e, t, n, r) { e || (e = new S); for (var o = new Qe(e, Oe(n), [n, r]), a = 0; a < t.length; a++) { var i = t[a]; o = o.update(e, 0, void 0, i[0], i[1]) } return o } function lt(e, t, n, r) { for (var o = 0, a = 0, i = new Array(n), s = 0, u = 1, c = t.length; s < c; s++, u <<= 1) { var l = t[s]; void 0 !== l && s !== r && (o |= u, i[a++] = l) } return new Ge(e, o, i) } function pt(e, t, n, r, o) { for (var a = 0, i = new Array(g), s = 0; 0 !== n; s++, n >>>= 1)i[s] = 1 & n ? t[a++] : void 0; return i[r] = o, new Ze(e, a + 1, i) } function ft(e, t, n) { for (var o = [], a = 0; a < n.length; a++) { var s = n[a], u = r(s); i(s) || (u = u.map((function (e) { return he(e) }))), o.push(u) } return mt(e, t, o) } function ht(e, t, n) { return e && e.mergeDeep && i(t) ? e.mergeDeep(t) : ge(e, t) ? e : t } function dt(e) { return function (t, n, r) { if (t && t.mergeDeepWith && i(n)) return t.mergeDeepWith(e, n); var o = e(t, n, r); return ge(t, o) ? t : o } } function mt(e, t, n) { return 0 === (n = n.filter((function (e) { return 0 !== e.size }))).length ? e : 0 !== e.size || e.__ownerID || 1 !== n.length ? e.withMutations((function (e) { for (var r = t ? function (n, r) { e.update(r, b, (function (e) { return e === b ? n : t(e, n, r) })) } : function (t, n) { e.set(n, t) }, o = 0; o < n.length; o++)n[o].forEach(r) })) : e.constructor(n[0]) } function vt(e, t, n, r) { var o = e === b, a = t.next(); if (a.done) { var i = o ? n : e, s = r(i); return s === i ? e : s } _e(o || e && e.set, "invalid keyPath"); var u = a.value, c = o ? b : e.get(u, b), l = vt(c, t, n, r); return l === c ? e : l === b ? e.remove(u) : (o ? ot() : e).set(u, l) } function gt(e) { return e = (e = (858993459 & (e -= e >> 1 & 1431655765)) + (e >> 2 & 858993459)) + (e >> 4) & 252645135, e += e >> 8, 127 & (e += e >> 16) } function yt(e, t, n, r) { var o = r ? e : C(e); return o[t] = n, o } function bt(e, t, n, r) { var o = e.length + 1; if (r && t + 1 === o) return e[t] = n, e; for (var a = new Array(o), i = 0, s = 0; s < o; s++)s === t ? (a[s] = n, i = -1) : a[s] = e[s + i]; return a } function _t(e, t, n) { var r = e.length - 1; if (n && t === r) return e.pop(), e; for (var o = new Array(r), a = 0, i = 0; i < r; i++)i === t && (a = 1), o[i] = e[i + a]; return o } Ke[$e] = !0, Ke[m] = Ke.remove, Ke.removeIn = Ke.deleteIn, Ye.prototype.get = function (e, t, n, r) { for (var o = this.entries, a = 0, i = o.length; a < i; a++)if (ge(n, o[a][0])) return o[a][1]; return r }, Ye.prototype.update = function (e, t, n, r, o, a, i) { for (var s = o === b, u = this.entries, c = 0, l = u.length; c < l && !ge(r, u[c][0]); c++); var p = c < l; if (p ? u[c][1] === o : s) return this; if (E(i), (s || !p) && E(a), !s || 1 !== u.length) { if (!p && !s && u.length >= wt) return ct(e, u, r, o); var f = e && e === this.ownerID, h = f ? u : C(u); return p ? s ? c === l - 1 ? h.pop() : h[c] = h.pop() : h[c] = [r, o] : h.push([r, o]), f ? (this.entries = h, this) : new Ye(e, h) } }, Ge.prototype.get = function (e, t, n, r) { void 0 === t && (t = Oe(n)); var o = 1 << ((0 === e ? t : t >>> e) & y), a = this.bitmap; return 0 == (a & o) ? r : this.nodes[gt(a & o - 1)].get(e + v, t, n, r) }, Ge.prototype.update = function (e, t, n, r, o, a, i) { void 0 === n && (n = Oe(r)); var s = (0 === t ? n : n >>> t) & y, u = 1 << s, c = this.bitmap, l = 0 != (c & u); if (!l && o === b) return this; var p = gt(c & u - 1), f = this.nodes, h = l ? f[p] : void 0, d = it(h, e, t + v, n, r, o, a, i); if (d === h) return this; if (!l && d && f.length >= xt) return pt(e, f, c, s, d); if (l && !d && 2 === f.length && st(f[1 ^ p])) return f[1 ^ p]; if (l && d && 1 === f.length && st(d)) return d; var m = e && e === this.ownerID, g = l ? d ? c : c ^ u : c | u, _ = l ? d ? yt(f, p, d, m) : _t(f, p, m) : bt(f, p, d, m); return m ? (this.bitmap = g, this.nodes = _, this) : new Ge(e, g, _) }, Ze.prototype.get = function (e, t, n, r) { void 0 === t && (t = Oe(n)); var o = (0 === e ? t : t >>> e) & y, a = this.nodes[o]; return a ? a.get(e + v, t, n, r) : r }, Ze.prototype.update = function (e, t, n, r, o, a, i) { void 0 === n && (n = Oe(r)); var s = (0 === t ? n : n >>> t) & y, u = o === b, c = this.nodes, l = c[s]; if (u && !l) return this; var p = it(l, e, t + v, n, r, o, a, i); if (p === l) return this; var f = this.count; if (l) { if (!p && --f < Et) return lt(e, c, f, s) } else f++; var h = e && e === this.ownerID, d = yt(c, s, p, h); return h ? (this.count = f, this.nodes = d, this) : new Ze(e, f, d) }, Xe.prototype.get = function (e, t, n, r) { for (var o = this.entries, a = 0, i = o.length; a < i; a++)if (ge(n, o[a][0])) return o[a][1]; return r }, Xe.prototype.update = function (e, t, n, r, o, a, i) { void 0 === n && (n = Oe(r)); var s = o === b; if (n !== this.keyHash) return s ? this : (E(i), E(a), ut(this, e, t, n, [r, o])); for (var u = this.entries, c = 0, l = u.length; c < l && !ge(r, u[c][0]); c++); var p = c < l; if (p ? u[c][1] === o : s) return this; if (E(i), (s || !p) && E(a), s && 2 === l) return new Qe(e, this.keyHash, u[1 ^ c]); var f = e && e === this.ownerID, h = f ? u : C(u); return p ? s ? c === l - 1 ? h.pop() : h[c] = h.pop() : h[c] = [r, o] : h.push([r, o]), f ? (this.entries = h, this) : new Xe(e, this.keyHash, h) }, Qe.prototype.get = function (e, t, n, r) { return ge(n, this.entry[0]) ? this.entry[1] : r }, Qe.prototype.update = function (e, t, n, r, o, a, i) { var s = o === b, u = ge(r, this.entry[0]); return (u ? o === this.entry[1] : s) ? this : (E(i), s ? void E(a) : u ? e && e === this.ownerID ? (this.entry[1] = o, this) : new Qe(e, this.keyHash, [r, o]) : (E(a), ut(this, e, t, Oe(r), [r, o]))) }, Ye.prototype.iterate = Xe.prototype.iterate = function (e, t) { for (var n = this.entries, r = 0, o = n.length - 1; r <= o; r++)if (!1 === e(n[t ? o - r : r])) return !1 }, Ge.prototype.iterate = Ze.prototype.iterate = function (e, t) { for (var n = this.nodes, r = 0, o = n.length - 1; r <= o; r++) { var a = n[t ? o - r : r]; if (a && !1 === a.iterate(e, t)) return !1 } }, Qe.prototype.iterate = function (e, t) { return e(this.entry) }, t(et, F), et.prototype.next = function () { for (var e = this._type, t = this._stack; t;) { var n, r = t.node, o = t.index++; if (r.entry) { if (0 === o) return tt(e, r.entry) } else if (r.entries) { if (o <= (n = r.entries.length - 1)) return tt(e, r.entries[this._reverse ? n - o : o]) } else if (o <= (n = r.nodes.length - 1)) { var a = r.nodes[this._reverse ? n - o : o]; if (a) { if (a.entry) return tt(e, a.entry); t = this._stack = nt(a, t) } continue } t = this._stack = this._stack.__prev } return q() }; var wt = g / 4, xt = g / 2, Et = g / 4; function St(e) { var t = Mt(); if (null == e) return t; if (Ct(e)) return e; var n = o(e), r = n.size; return 0 === r ? t : (Ve(r), r > 0 && r < g ? Nt(0, r, v, null, new Ot(n.toArray())) : t.withMutations((function (e) { e.setSize(r), n.forEach((function (t, n) { return e.set(n, t) })) }))) } function Ct(e) { return !(!e || !e[At]) } t(St, Se), St.of = function () { return this(arguments) }, St.prototype.toString = function () { return this.__toString("List [", "]") }, St.prototype.get = function (e, t) { if ((e = k(this, e)) >= 0 && e < this.size) { var n = Bt(this, e += this._origin); return n && n.array[e & y] } return t }, St.prototype.set = function (e, t) { return Rt(this, e, t) }, St.prototype.remove = function (e) { return this.has(e) ? 0 === e ? this.shift() : e === this.size - 1 ? this.pop() : this.splice(e, 1) : this }, St.prototype.insert = function (e, t) { return this.splice(e, 0, t) }, St.prototype.clear = function () { return 0 === this.size ? this : this.__ownerID ? (this.size = this._origin = this._capacity = 0, this._level = v, this._root = this._tail = null, this.__hash = void 0, this.__altered = !0, this) : Mt() }, St.prototype.push = function () { var e = arguments, t = this.size; return this.withMutations((function (n) { Ft(n, 0, t + e.length); for (var r = 0; r < e.length; r++)n.set(t + r, e[r]) })) }, St.prototype.pop = function () { return Ft(this, 0, -1) }, St.prototype.unshift = function () { var e = arguments; return this.withMutations((function (t) { Ft(t, -e.length); for (var n = 0; n < e.length; n++)t.set(n, e[n]) })) }, St.prototype.shift = function () { return Ft(this, 1) }, St.prototype.merge = function () { return Ut(this, void 0, arguments) }, St.prototype.mergeWith = function (t) { return Ut(this, t, e.call(arguments, 1)) }, St.prototype.mergeDeep = function () { return Ut(this, ht, arguments) }, St.prototype.mergeDeepWith = function (t) { var n = e.call(arguments, 1); return Ut(this, dt(t), n) }, St.prototype.setSize = function (e) { return Ft(this, 0, e) }, St.prototype.slice = function (e, t) { var n = this.size; return j(e, t, n) ? this : Ft(this, T(e, n), I(t, n)) }, St.prototype.__iterator = function (e, t) { var n = 0, r = Pt(this, t); return new F((function () { var t = r(); return t === It ? q() : U(e, n++, t) })) }, St.prototype.__iterate = function (e, t) { for (var n, r = 0, o = Pt(this, t); (n = o()) !== It && !1 !== e(n, r++, this);); return r }, St.prototype.__ensureOwner = function (e) { return e === this.__ownerID ? this : e ? Nt(this._origin, this._capacity, this._level, this._root, this._tail, e, this.__hash) : (this.__ownerID = e, this) }, St.isList = Ct; var At = "@@__IMMUTABLE_LIST__@@", kt = St.prototype; function Ot(e, t) { this.array = e, this.ownerID = t } kt[At] = !0, kt[m] = kt.remove, kt.setIn = Ke.setIn, kt.deleteIn = kt.removeIn = Ke.removeIn, kt.update = Ke.update, kt.updateIn = Ke.updateIn, kt.mergeIn = Ke.mergeIn, kt.mergeDeepIn = Ke.mergeDeepIn, kt.withMutations = Ke.withMutations, kt.asMutable = Ke.asMutable, kt.asImmutable = Ke.asImmutable, kt.wasAltered = Ke.wasAltered, Ot.prototype.removeBefore = function (e, t, n) { if (n === t ? 1 << t : 0 === this.array.length) return this; var r = n >>> t & y; if (r >= this.array.length) return new Ot([], e); var o, a = 0 === r; if (t > 0) { var i = this.array[r]; if ((o = i && i.removeBefore(e, t - v, n)) === i && a) return this } if (a && !o) return this; var s = Lt(this, e); if (!a) for (var u = 0; u < r; u++)s.array[u] = void 0; return o && (s.array[r] = o), s }, Ot.prototype.removeAfter = function (e, t, n) { if (n === (t ? 1 << t : 0) || 0 === this.array.length) return this; var r, o = n - 1 >>> t & y; if (o >= this.array.length) return this; if (t > 0) { var a = this.array[o]; if ((r = a && a.removeAfter(e, t - v, n)) === a && o === this.array.length - 1) return this } var i = Lt(this, e); return i.array.splice(o + 1), r && (i.array[o] = r), i }; var jt, Tt, It = {}; function Pt(e, t) { var n = e._origin, r = e._capacity, o = qt(r), a = e._tail; return i(e._root, e._level, 0); function i(e, t, n) { return 0 === t ? s(e, n) : u(e, t, n) } function s(e, i) { var s = i === o ? a && a.array : e && e.array, u = i > n ? 0 : n - i, c = r - i; return c > g && (c = g), function () { if (u === c) return It; var e = t ? --c : u++; return s && s[e] } } function u(e, o, a) { var s, u = e && e.array, c = a > n ? 0 : n - a >> o, l = 1 + (r - a >> o); return l > g && (l = g), function () { for (; ;) { if (s) { var e = s(); if (e !== It) return e; s = null } if (c === l) return It; var n = t ? --l : c++; s = i(u && u[n], o - v, a + (n << o)) } } } } function Nt(e, t, n, r, o, a, i) { var s = Object.create(kt); return s.size = t - e, s._origin = e, s._capacity = t, s._level = n, s._root = r, s._tail = o, s.__ownerID = a, s.__hash = i, s.__altered = !1, s } function Mt() { return jt || (jt = Nt(0, 0, v)) } function Rt(e, t, n) { if ((t = k(e, t)) != t) return e; if (t >= e.size || t < 0) return e.withMutations((function (e) { t < 0 ? Ft(e, t).set(0, n) : Ft(e, 0, t + 1).set(t, n) })); t += e._origin; var r = e._tail, o = e._root, a = x(w); return t >= qt(e._capacity) ? r = Dt(r, e.__ownerID, 0, t, n, a) : o = Dt(o, e.__ownerID, e._level, t, n, a), a.value ? e.__ownerID ? (e._root = o, e._tail = r, e.__hash = void 0, e.__altered = !0, e) : Nt(e._origin, e._capacity, e._level, o, r) : e } function Dt(e, t, n, r, o, a) { var i, s = r >>> n & y, u = e && s < e.array.length; if (!u && void 0 === o) return e; if (n > 0) { var c = e && e.array[s], l = Dt(c, t, n - v, r, o, a); return l === c ? e : ((i = Lt(e, t)).array[s] = l, i) } return u && e.array[s] === o ? e : (E(a), i = Lt(e, t), void 0 === o && s === i.array.length - 1 ? i.array.pop() : i.array[s] = o, i) } function Lt(e, t) { return t && e && t === e.ownerID ? e : new Ot(e ? e.array.slice() : [], t) } function Bt(e, t) { if (t >= qt(e._capacity)) return e._tail; if (t < 1 << e._level + v) { for (var n = e._root, r = e._level; n && r > 0;)n = n.array[t >>> r & y], r -= v; return n } } function Ft(e, t, n) { void 0 !== t && (t |= 0), void 0 !== n && (n |= 0); var r = e.__ownerID || new S, o = e._origin, a = e._capacity, i = o + t, s = void 0 === n ? a : n < 0 ? a + n : o + n; if (i === o && s === a) return e; if (i >= s) return e.clear(); for (var u = e._level, c = e._root, l = 0; i + l < 0;)c = new Ot(c && c.array.length ? [void 0, c] : [], r), l += 1 << (u += v); l && (i += l, o += l, s += l, a += l); for (var p = qt(a), f = qt(s); f >= 1 << u + v;)c = new Ot(c && c.array.length ? [c] : [], r), u += v; var h = e._tail, d = f < p ? Bt(e, s - 1) : f > p ? new Ot([], r) : h; if (h && f > p && i < a && h.array.length) { for (var m = c = Lt(c, r), g = u; g > v; g -= v) { var b = p >>> g & y; m = m.array[b] = Lt(m.array[b], r) } m.array[p >>> v & y] = h } if (s < a && (d = d && d.removeAfter(r, 0, s)), i >= f) i -= f, s -= f, u = v, c = null, d = d && d.removeBefore(r, 0, i); else if (i > o || f < p) { for (l = 0; c;) { var _ = i >>> u & y; if (_ !== f >>> u & y) break; _ && (l += (1 << u) * _), u -= v, c = c.array[_] } c && i > o && (c = c.removeBefore(r, u, i - l)), c && f < p && (c = c.removeAfter(r, u, f - l)), l && (i -= l, s -= l) } return e.__ownerID ? (e.size = s - i, e._origin = i, e._capacity = s, e._level = u, e._root = c, e._tail = d, e.__hash = void 0, e.__altered = !0, e) : Nt(i, s, u, c, d) } function Ut(e, t, n) { for (var r = [], a = 0, s = 0; s < n.length; s++) { var u = n[s], c = o(u); c.size > a && (a = c.size), i(u) || (c = c.map((function (e) { return he(e) }))), r.push(c) } return a > e.size && (e = e.setSize(a)), mt(e, t, r) } function qt(e) { return e < g ? 0 : e - 1 >>> v << v } function zt(e) { return null == e ? Ht() : Vt(e) ? e : Ht().withMutations((function (t) { var n = r(e); Ve(n.size), n.forEach((function (e, n) { return t.set(n, e) })) })) } function Vt(e) { return He(e) && l(e) } function Wt(e, t, n, r) { var o = Object.create(zt.prototype); return o.size = e ? e.size : 0, o._map = e, o._list = t, o.__ownerID = n, o.__hash = r, o } function Ht() { return Tt || (Tt = Wt(ot(), Mt())) } function Jt(e, t, n) { var r, o, a = e._map, i = e._list, s = a.get(t), u = void 0 !== s; if (n === b) { if (!u) return e; i.size >= g && i.size >= 2 * a.size ? (r = (o = i.filter((function (e, t) { return void 0 !== e && s !== t }))).toKeyedSeq().map((function (e) { return e[0] })).flip().toMap(), e.__ownerID && (r.__ownerID = o.__ownerID = e.__ownerID)) : (r = a.remove(t), o = s === i.size - 1 ? i.pop() : i.set(s, void 0)) } else if (u) { if (n === i.get(s)[1]) return e; r = a, o = i.set(s, [t, n]) } else r = a.set(t, i.size), o = i.set(i.size, [t, n]); return e.__ownerID ? (e.size = r.size, e._map = r, e._list = o, e.__hash = void 0, e) : Wt(r, o) } function $t(e, t) { this._iter = e, this._useKeys = t, this.size = e.size } function Kt(e) { this._iter = e, this.size = e.size } function Yt(e) { this._iter = e, this.size = e.size } function Gt(e) { this._iter = e, this.size = e.size } function Zt(e) { var t = bn(e); return t._iter = e, t.size = e.size, t.flip = function () { return e }, t.reverse = function () { var t = e.reverse.apply(this); return t.flip = function () { return e.reverse() }, t }, t.has = function (t) { return e.includes(t) }, t.includes = function (t) { return e.has(t) }, t.cacheResult = _n, t.__iterateUncached = function (t, n) { var r = this; return e.__iterate((function (e, n) { return !1 !== t(n, e, r) }), n) }, t.__iteratorUncached = function (t, n) { if (t === R) { var r = e.__iterator(t, n); return new F((function () { var e = r.next(); if (!e.done) { var t = e.value[0]; e.value[0] = e.value[1], e.value[1] = t } return e })) } return e.__iterator(t === M ? N : M, n) }, t } function Xt(e, t, n) { var r = bn(e); return r.size = e.size, r.has = function (t) { return e.has(t) }, r.get = function (r, o) { var a = e.get(r, b); return a === b ? o : t.call(n, a, r, e) }, r.__iterateUncached = function (r, o) { var a = this; return e.__iterate((function (e, o, i) { return !1 !== r(t.call(n, e, o, i), o, a) }), o) }, r.__iteratorUncached = function (r, o) { var a = e.__iterator(R, o); return new F((function () { var o = a.next(); if (o.done) return o; var i = o.value, s = i[0]; return U(r, s, t.call(n, i[1], s, e), o) })) }, r } function Qt(e, t) { var n = bn(e); return n._iter = e, n.size = e.size, n.reverse = function () { return e }, e.flip && (n.flip = function () { var t = Zt(e); return t.reverse = function () { return e.flip() }, t }), n.get = function (n, r) { return e.get(t ? n : -1 - n, r) }, n.has = function (n) { return e.has(t ? n : -1 - n) }, n.includes = function (t) { return e.includes(t) }, n.cacheResult = _n, n.__iterate = function (t, n) { var r = this; return e.__iterate((function (e, n) { return t(e, n, r) }), !n) }, n.__iterator = function (t, n) { return e.__iterator(t, !n) }, n } function en(e, t, n, r) { var o = bn(e); return r && (o.has = function (r) { var o = e.get(r, b); return o !== b && !!t.call(n, o, r, e) }, o.get = function (r, o) { var a = e.get(r, b); return a !== b && t.call(n, a, r, e) ? a : o }), o.__iterateUncached = function (o, a) { var i = this, s = 0; return e.__iterate((function (e, a, u) { if (t.call(n, e, a, u)) return s++, o(e, r ? a : s - 1, i) }), a), s }, o.__iteratorUncached = function (o, a) { var i = e.__iterator(R, a), s = 0; return new F((function () { for (; ;) { var a = i.next(); if (a.done) return a; var u = a.value, c = u[0], l = u[1]; if (t.call(n, l, c, e)) return U(o, r ? c : s++, l, a) } })) }, o } function tn(e, t, n) { var r = We().asMutable(); return e.__iterate((function (o, a) { r.update(t.call(n, o, a, e), 0, (function (e) { return e + 1 })) })), r.asImmutable() } function nn(e, t, n) { var r = s(e), o = (l(e) ? zt() : We()).asMutable(); e.__iterate((function (a, i) { o.update(t.call(n, a, i, e), (function (e) { return (e = e || []).push(r ? [i, a] : a), e })) })); var a = yn(e); return o.map((function (t) { return mn(e, a(t)) })) } function rn(e, t, n, r) { var o = e.size; if (void 0 !== t && (t |= 0), void 0 !== n && (n === 1 / 0 ? n = o : n |= 0), j(t, n, o)) return e; var a = T(t, o), i = I(n, o); if (a != a || i != i) return rn(e.toSeq().cacheResult(), t, n, r); var s, u = i - a; u == u && (s = u < 0 ? 0 : u); var c = bn(e); return c.size = 0 === s ? s : e.size && s || void 0, !r && ae(e) && s >= 0 && (c.get = function (t, n) { return (t = k(this, t)) >= 0 && t < s ? e.get(t + a, n) : n }), c.__iterateUncached = function (t, n) { var o = this; if (0 === s) return 0; if (n) return this.cacheResult().__iterate(t, n); var i = 0, u = !0, c = 0; return e.__iterate((function (e, n) { if (!u || !(u = i++ < a)) return c++, !1 !== t(e, r ? n : c - 1, o) && c !== s })), c }, c.__iteratorUncached = function (t, n) { if (0 !== s && n) return this.cacheResult().__iterator(t, n); var o = 0 !== s && e.__iterator(t, n), i = 0, u = 0; return new F((function () { for (; i++ < a;)o.next(); if (++u > s) return q(); var e = o.next(); return r || t === M ? e : U(t, u - 1, t === N ? void 0 : e.value[1], e) })) }, c } function on(e, t, n) { var r = bn(e); return r.__iterateUncached = function (r, o) { var a = this; if (o) return this.cacheResult().__iterate(r, o); var i = 0; return e.__iterate((function (e, o, s) { return t.call(n, e, o, s) && ++i && r(e, o, a) })), i }, r.__iteratorUncached = function (r, o) { var a = this; if (o) return this.cacheResult().__iterator(r, o); var i = e.__iterator(R, o), s = !0; return new F((function () { if (!s) return q(); var e = i.next(); if (e.done) return e; var o = e.value, u = o[0], c = o[1]; return t.call(n, c, u, a) ? r === R ? e : U(r, u, c, e) : (s = !1, q()) })) }, r } function an(e, t, n, r) { var o = bn(e); return o.__iterateUncached = function (o, a) { var i = this; if (a) return this.cacheResult().__iterate(o, a); var s = !0, u = 0; return e.__iterate((function (e, a, c) { if (!s || !(s = t.call(n, e, a, c))) return u++, o(e, r ? a : u - 1, i) })), u }, o.__iteratorUncached = function (o, a) { var i = this; if (a) return this.cacheResult().__iterator(o, a); var s = e.__iterator(R, a), u = !0, c = 0; return new F((function () { var e, a, l; do { if ((e = s.next()).done) return r || o === M ? e : U(o, c++, o === N ? void 0 : e.value[1], e); var p = e.value; a = p[0], l = p[1], u && (u = t.call(n, l, a, i)) } while (u); return o === R ? e : U(o, a, l, e) })) }, o } function sn(e, t) { var n = s(e), o = [e].concat(t).map((function (e) { return i(e) ? n && (e = r(e)) : e = n ? se(e) : ue(Array.isArray(e) ? e : [e]), e })).filter((function (e) { return 0 !== e.size })); if (0 === o.length) return e; if (1 === o.length) { var a = o[0]; if (a === e || n && s(a) || u(e) && u(a)) return a } var c = new te(o); return n ? c = c.toKeyedSeq() : u(e) || (c = c.toSetSeq()), (c = c.flatten(!0)).size = o.reduce((function (e, t) { if (void 0 !== e) { var n = t.size; if (void 0 !== n) return e + n } }), 0), c } function un(e, t, n) { var r = bn(e); return r.__iterateUncached = function (r, o) { var a = 0, s = !1; function u(e, c) { var l = this; e.__iterate((function (e, o) { return (!t || c < t) && i(e) ? u(e, c + 1) : !1 === r(e, n ? o : a++, l) && (s = !0), !s }), o) } return u(e, 0), a }, r.__iteratorUncached = function (r, o) { var a = e.__iterator(r, o), s = [], u = 0; return new F((function () { for (; a;) { var e = a.next(); if (!1 === e.done) { var c = e.value; if (r === R && (c = c[1]), t && !(s.length < t) || !i(c)) return n ? e : U(r, u++, c, e); s.push(a), a = c.__iterator(r, o) } else a = s.pop() } return q() })) }, r } function cn(e, t, n) { var r = yn(e); return e.toSeq().map((function (o, a) { return r(t.call(n, o, a, e)) })).flatten(!0) } function ln(e, t) { var n = bn(e); return n.size = e.size && 2 * e.size - 1, n.__iterateUncached = function (n, r) { var o = this, a = 0; return e.__iterate((function (e, r) { return (!a || !1 !== n(t, a++, o)) && !1 !== n(e, a++, o) }), r), a }, n.__iteratorUncached = function (n, r) { var o, a = e.__iterator(M, r), i = 0; return new F((function () { return (!o || i % 2) && (o = a.next()).done ? o : i % 2 ? U(n, i++, t) : U(n, i++, o.value, o) })) }, n } function pn(e, t, n) { t || (t = wn); var r = s(e), o = 0, a = e.toSeq().map((function (t, r) { return [r, t, o++, n ? n(t, r, e) : t] })).toArray(); return a.sort((function (e, n) { return t(e[3], n[3]) || e[2] - n[2] })).forEach(r ? function (e, t) { a[t].length = 2 } : function (e, t) { a[t] = e[1] }), r ? K(a) : u(e) ? Y(a) : G(a) } function fn(e, t, n) { if (t || (t = wn), n) { var r = e.toSeq().map((function (t, r) { return [t, n(t, r, e)] })).reduce((function (e, n) { return hn(t, e[1], n[1]) ? n : e })); return r && r[0] } return e.reduce((function (e, n) { return hn(t, e, n) ? n : e })) } function hn(e, t, n) { var r = e(n, t); return 0 === r && n !== t && (null == n || n != n) || r > 0 } function dn(e, t, r) { var o = bn(e); return o.size = new te(r).map((function (e) { return e.size })).min(), o.__iterate = function (e, t) { for (var n, r = this.__iterator(M, t), o = 0; !(n = r.next()).done && !1 !== e(n.value, o++, this);); return o }, o.__iteratorUncached = function (e, o) { var a = r.map((function (e) { return e = n(e), W(o ? e.reverse() : e) })), i = 0, s = !1; return new F((function () { var n; return s || (n = a.map((function (e) { return e.next() })), s = n.some((function (e) { return e.done }))), s ? q() : U(e, i++, t.apply(null, n.map((function (e) { return e.value })))) })) }, o } function mn(e, t) { return ae(e) ? t : e.constructor(t) } function vn(e) { if (e !== Object(e)) throw new TypeError("Expected [K, V] tuple: " + e) } function gn(e) { return Ve(e.size), A(e) } function yn(e) { return s(e) ? r : u(e) ? o : a } function bn(e) { return Object.create((s(e) ? K : u(e) ? Y : G).prototype) } function _n() { return this._iter.cacheResult ? (this._iter.cacheResult(), this.size = this._iter.size, this) : $.prototype.cacheResult.call(this) } function wn(e, t) { return e > t ? 1 : e < t ? -1 : 0 } function xn(e) { var t = W(e); if (!t) { if (!J(e)) throw new TypeError("Expected iterable or array-like: " + e); t = W(n(e)) } return t } function En(e, t) { var n, r = function (a) { if (a instanceof r) return a; if (!(this instanceof r)) return new r(a); if (!n) { n = !0; var i = Object.keys(e); kn(o, i), o.size = i.length, o._name = t, o._keys = i, o._defaultValues = e } this._map = We(a) }, o = r.prototype = Object.create(Sn); return o.constructor = r, r } t(zt, We), zt.of = function () { return this(arguments) }, zt.prototype.toString = function () { return this.__toString("OrderedMap {", "}") }, zt.prototype.get = function (e, t) { var n = this._map.get(e); return void 0 !== n ? this._list.get(n)[1] : t }, zt.prototype.clear = function () { return 0 === this.size ? this : this.__ownerID ? (this.size = 0, this._map.clear(), this._list.clear(), this) : Ht() }, zt.prototype.set = function (e, t) { return Jt(this, e, t) }, zt.prototype.remove = function (e) { return Jt(this, e, b) }, zt.prototype.wasAltered = function () { return this._map.wasAltered() || this._list.wasAltered() }, zt.prototype.__iterate = function (e, t) { var n = this; return this._list.__iterate((function (t) { return t && e(t[1], t[0], n) }), t) }, zt.prototype.__iterator = function (e, t) { return this._list.fromEntrySeq().__iterator(e, t) }, zt.prototype.__ensureOwner = function (e) { if (e === this.__ownerID) return this; var t = this._map.__ensureOwner(e), n = this._list.__ensureOwner(e); return e ? Wt(t, n, e, this.__hash) : (this.__ownerID = e, this._map = t, this._list = n, this) }, zt.isOrderedMap = Vt, zt.prototype[d] = !0, zt.prototype[m] = zt.prototype.remove, t($t, K), $t.prototype.get = function (e, t) { return this._iter.get(e, t) }, $t.prototype.has = function (e) { return this._iter.has(e) }, $t.prototype.valueSeq = function () { return this._iter.valueSeq() }, $t.prototype.reverse = function () { var e = this, t = Qt(this, !0); return this._useKeys || (t.valueSeq = function () { return e._iter.toSeq().reverse() }), t }, $t.prototype.map = function (e, t) { var n = this, r = Xt(this, e, t); return this._useKeys || (r.valueSeq = function () { return n._iter.toSeq().map(e, t) }), r }, $t.prototype.__iterate = function (e, t) { var n, r = this; return this._iter.__iterate(this._useKeys ? function (t, n) { return e(t, n, r) } : (n = t ? gn(this) : 0, function (o) { return e(o, t ? --n : n++, r) }), t) }, $t.prototype.__iterator = function (e, t) { if (this._useKeys) return this._iter.__iterator(e, t); var n = this._iter.__iterator(M, t), r = t ? gn(this) : 0; return new F((function () { var o = n.next(); return o.done ? o : U(e, t ? --r : r++, o.value, o) })) }, $t.prototype[d] = !0, t(Kt, Y), Kt.prototype.includes = function (e) { return this._iter.includes(e) }, Kt.prototype.__iterate = function (e, t) { var n = this, r = 0; return this._iter.__iterate((function (t) { return e(t, r++, n) }), t) }, Kt.prototype.__iterator = function (e, t) { var n = this._iter.__iterator(M, t), r = 0; return new F((function () { var t = n.next(); return t.done ? t : U(e, r++, t.value, t) })) }, t(Yt, G), Yt.prototype.has = function (e) { return this._iter.includes(e) }, Yt.prototype.__iterate = function (e, t) { var n = this; return this._iter.__iterate((function (t) { return e(t, t, n) }), t) }, Yt.prototype.__iterator = function (e, t) { var n = this._iter.__iterator(M, t); return new F((function () { var t = n.next(); return t.done ? t : U(e, t.value, t.value, t) })) }, t(Gt, K), Gt.prototype.entrySeq = function () { return this._iter.toSeq() }, Gt.prototype.__iterate = function (e, t) { var n = this; return this._iter.__iterate((function (t) { if (t) { vn(t); var r = i(t); return e(r ? t.get(1) : t[1], r ? t.get(0) : t[0], n) } }), t) }, Gt.prototype.__iterator = function (e, t) { var n = this._iter.__iterator(M, t); return new F((function () { for (; ;) { var t = n.next(); if (t.done) return t; var r = t.value; if (r) { vn(r); var o = i(r); return U(e, o ? r.get(0) : r[0], o ? r.get(1) : r[1], t) } } })) }, Kt.prototype.cacheResult = $t.prototype.cacheResult = Yt.prototype.cacheResult = Gt.prototype.cacheResult = _n, t(En, Ee), En.prototype.toString = function () { return this.__toString(An(this) + " {", "}") }, En.prototype.has = function (e) { return this._defaultValues.hasOwnProperty(e) }, En.prototype.get = function (e, t) { if (!this.has(e)) return t; var n = this._defaultValues[e]; return this._map ? this._map.get(e, n) : n }, En.prototype.clear = function () { if (this.__ownerID) return this._map && this._map.clear(), this; var e = this.constructor; return e._empty || (e._empty = Cn(this, ot())) }, En.prototype.set = function (e, t) { if (!this.has(e)) throw new Error('Cannot set unknown key "' + e + '" on ' + An(this)); if (this._map && !this._map.has(e) && t === this._defaultValues[e]) return this; var n = this._map && this._map.set(e, t); return this.__ownerID || n === this._map ? this : Cn(this, n) }, En.prototype.remove = function (e) { if (!this.has(e)) return this; var t = this._map && this._map.remove(e); return this.__ownerID || t === this._map ? this : Cn(this, t) }, En.prototype.wasAltered = function () { return this._map.wasAltered() }, En.prototype.__iterator = function (e, t) { var n = this; return r(this._defaultValues).map((function (e, t) { return n.get(t) })).__iterator(e, t) }, En.prototype.__iterate = function (e, t) { var n = this; return r(this._defaultValues).map((function (e, t) { return n.get(t) })).__iterate(e, t) }, En.prototype.__ensureOwner = function (e) { if (e === this.__ownerID) return this; var t = this._map && this._map.__ensureOwner(e); return e ? Cn(this, t, e) : (this.__ownerID = e, this._map = t, this) }; var Sn = En.prototype; function Cn(e, t, n) { var r = Object.create(Object.getPrototypeOf(e)); return r._map = t, r.__ownerID = n, r } function An(e) { return e._name || e.constructor.name || "Record" } function kn(e, t) { try { t.forEach(On.bind(void 0, e)) } catch (e) { } } function On(e, t) { Object.defineProperty(e, t, { get: function () { return this.get(t) }, set: function (e) { _e(this.__ownerID, "Cannot set on an immutable record."), this.set(t, e) } }) } function jn(e) { return null == e ? Dn() : Tn(e) && !l(e) ? e : Dn().withMutations((function (t) { var n = a(e); Ve(n.size), n.forEach((function (e) { return t.add(e) })) })) } function Tn(e) { return !(!e || !e[Pn]) } Sn[m] = Sn.remove, Sn.deleteIn = Sn.removeIn = Ke.removeIn, Sn.merge = Ke.merge, Sn.mergeWith = Ke.mergeWith, Sn.mergeIn = Ke.mergeIn, Sn.mergeDeep = Ke.mergeDeep, Sn.mergeDeepWith = Ke.mergeDeepWith, Sn.mergeDeepIn = Ke.mergeDeepIn, Sn.setIn = Ke.setIn, Sn.update = Ke.update, Sn.updateIn = Ke.updateIn, Sn.withMutations = Ke.withMutations, Sn.asMutable = Ke.asMutable, Sn.asImmutable = Ke.asImmutable, t(jn, Ce), jn.of = function () { return this(arguments) }, jn.fromKeys = function (e) { return this(r(e).keySeq()) }, jn.prototype.toString = function () { return this.__toString("Set {", "}") }, jn.prototype.has = function (e) { return this._map.has(e) }, jn.prototype.add = function (e) { return Mn(this, this._map.set(e, !0)) }, jn.prototype.remove = function (e) { return Mn(this, this._map.remove(e)) }, jn.prototype.clear = function () { return Mn(this, this._map.clear()) }, jn.prototype.union = function () { var t = e.call(arguments, 0); return 0 === (t = t.filter((function (e) { return 0 !== e.size }))).length ? this : 0 !== this.size || this.__ownerID || 1 !== t.length ? this.withMutations((function (e) { for (var n = 0; n < t.length; n++)a(t[n]).forEach((function (t) { return e.add(t) })) })) : this.constructor(t[0]) }, jn.prototype.intersect = function () { var t = e.call(arguments, 0); if (0 === t.length) return this; t = t.map((function (e) { return a(e) })); var n = this; return this.withMutations((function (e) { n.forEach((function (n) { t.every((function (e) { return e.includes(n) })) || e.remove(n) })) })) }, jn.prototype.subtract = function () { var t = e.call(arguments, 0); if (0 === t.length) return this; t = t.map((function (e) { return a(e) })); var n = this; return this.withMutations((function (e) { n.forEach((function (n) { t.some((function (e) { return e.includes(n) })) && e.remove(n) })) })) }, jn.prototype.merge = function () { return this.union.apply(this, arguments) }, jn.prototype.mergeWith = function (t) { var n = e.call(arguments, 1); return this.union.apply(this, n) }, jn.prototype.sort = function (e) { return Ln(pn(this, e)) }, jn.prototype.sortBy = function (e, t) { return Ln(pn(this, t, e)) }, jn.prototype.wasAltered = function () { return this._map.wasAltered() }, jn.prototype.__iterate = function (e, t) { var n = this; return this._map.__iterate((function (t, r) { return e(r, r, n) }), t) }, jn.prototype.__iterator = function (e, t) { return this._map.map((function (e, t) { return t })).__iterator(e, t) }, jn.prototype.__ensureOwner = function (e) { if (e === this.__ownerID) return this; var t = this._map.__ensureOwner(e); return e ? this.__make(t, e) : (this.__ownerID = e, this._map = t, this) }, jn.isSet = Tn; var In, Pn = "@@__IMMUTABLE_SET__@@", Nn = jn.prototype; function Mn(e, t) { return e.__ownerID ? (e.size = t.size, e._map = t, e) : t === e._map ? e : 0 === t.size ? e.__empty() : e.__make(t) } function Rn(e, t) { var n = Object.create(Nn); return n.size = e ? e.size : 0, n._map = e, n.__ownerID = t, n } function Dn() { return In || (In = Rn(ot())) } function Ln(e) { return null == e ? zn() : Bn(e) ? e : zn().withMutations((function (t) { var n = a(e); Ve(n.size), n.forEach((function (e) { return t.add(e) })) })) } function Bn(e) { return Tn(e) && l(e) } Nn[Pn] = !0, Nn[m] = Nn.remove, Nn.mergeDeep = Nn.merge, Nn.mergeDeepWith = Nn.mergeWith, Nn.withMutations = Ke.withMutations, Nn.asMutable = Ke.asMutable, Nn.asImmutable = Ke.asImmutable, Nn.__empty = Dn, Nn.__make = Rn, t(Ln, jn), Ln.of = function () { return this(arguments) }, Ln.fromKeys = function (e) { return this(r(e).keySeq()) }, Ln.prototype.toString = function () { return this.__toString("OrderedSet {", "}") }, Ln.isOrderedSet = Bn; var Fn, Un = Ln.prototype; function qn(e, t) { var n = Object.create(Un); return n.size = e ? e.size : 0, n._map = e, n.__ownerID = t, n } function zn() { return Fn || (Fn = qn(Ht())) } function Vn(e) { return null == e ? Yn() : Wn(e) ? e : Yn().unshiftAll(e) } function Wn(e) { return !(!e || !e[Jn]) } Un[d] = !0, Un.__empty = zn, Un.__make = qn, t(Vn, Se), Vn.of = function () { return this(arguments) }, Vn.prototype.toString = function () { return this.__toString("Stack [", "]") }, Vn.prototype.get = function (e, t) { var n = this._head; for (e = k(this, e); n && e--;)n = n.next; return n ? n.value : t }, Vn.prototype.peek = function () { return this._head && this._head.value }, Vn.prototype.push = function () { if (0 === arguments.length) return this; for (var e = this.size + arguments.length, t = this._head, n = arguments.length - 1; n >= 0; n--)t = { value: arguments[n], next: t }; return this.__ownerID ? (this.size = e, this._head = t, this.__hash = void 0, this.__altered = !0, this) : Kn(e, t) }, Vn.prototype.pushAll = function (e) { if (0 === (e = o(e)).size) return this; Ve(e.size); var t = this.size, n = this._head; return e.reverse().forEach((function (e) { t++, n = { value: e, next: n } })), this.__ownerID ? (this.size = t, this._head = n, this.__hash = void 0, this.__altered = !0, this) : Kn(t, n) }, Vn.prototype.pop = function () { return this.slice(1) }, Vn.prototype.unshift = function () { return this.push.apply(this, arguments) }, Vn.prototype.unshiftAll = function (e) { return this.pushAll(e) }, Vn.prototype.shift = function () { return this.pop.apply(this, arguments) }, Vn.prototype.clear = function () { return 0 === this.size ? this : this.__ownerID ? (this.size = 0, this._head = void 0, this.__hash = void 0, this.__altered = !0, this) : Yn() }, Vn.prototype.slice = function (e, t) { if (j(e, t, this.size)) return this; var n = T(e, this.size); if (I(t, this.size) !== this.size) return Se.prototype.slice.call(this, e, t); for (var r = this.size - n, o = this._head; n--;)o = o.next; return this.__ownerID ? (this.size = r, this._head = o, this.__hash = void 0, this.__altered = !0, this) : Kn(r, o) }, Vn.prototype.__ensureOwner = function (e) { return e === this.__ownerID ? this : e ? Kn(this.size, this._head, e, this.__hash) : (this.__ownerID = e, this.__altered = !1, this) }, Vn.prototype.__iterate = function (e, t) { if (t) return this.reverse().__iterate(e); for (var n = 0, r = this._head; r && !1 !== e(r.value, n++, this);)r = r.next; return n }, Vn.prototype.__iterator = function (e, t) { if (t) return this.reverse().__iterator(e); var n = 0, r = this._head; return new F((function () { if (r) { var t = r.value; return r = r.next, U(e, n++, t) } return q() })) }, Vn.isStack = Wn; var Hn, Jn = "@@__IMMUTABLE_STACK__@@", $n = Vn.prototype; function Kn(e, t, n, r) { var o = Object.create($n); return o.size = e, o._head = t, o.__ownerID = n, o.__hash = r, o.__altered = !1, o } function Yn() { return Hn || (Hn = Kn(0)) } function Gn(e, t) { var n = function (n) { e.prototype[n] = t[n] }; return Object.keys(t).forEach(n), Object.getOwnPropertySymbols && Object.getOwnPropertySymbols(t).forEach(n), e } $n[Jn] = !0, $n.withMutations = Ke.withMutations, $n.asMutable = Ke.asMutable, $n.asImmutable = Ke.asImmutable, $n.wasAltered = Ke.wasAltered, n.Iterator = F, Gn(n, { toArray: function () { Ve(this.size); var e = new Array(this.size || 0); return this.valueSeq().__iterate((function (t, n) { e[n] = t })), e }, toIndexedSeq: function () { return new Kt(this) }, toJS: function () { return this.toSeq().map((function (e) { return e && "function" == typeof e.toJS ? e.toJS() : e })).__toJS() }, toJSON: function () { return this.toSeq().map((function (e) { return e && "function" == typeof e.toJSON ? e.toJSON() : e })).__toJS() }, toKeyedSeq: function () { return new $t(this, !0) }, toMap: function () { return We(this.toKeyedSeq()) }, toObject: function () { Ve(this.size); var e = {}; return this.__iterate((function (t, n) { e[n] = t })), e }, toOrderedMap: function () { return zt(this.toKeyedSeq()) }, toOrderedSet: function () { return Ln(s(this) ? this.valueSeq() : this) }, toSet: function () { return jn(s(this) ? this.valueSeq() : this) }, toSetSeq: function () { return new Yt(this) }, toSeq: function () { return u(this) ? this.toIndexedSeq() : s(this) ? this.toKeyedSeq() : this.toSetSeq() }, toStack: function () { return Vn(s(this) ? this.valueSeq() : this) }, toList: function () { return St(s(this) ? this.valueSeq() : this) }, toString: function () { return "[Iterable]" }, __toString: function (e, t) { return 0 === this.size ? e + t : e + " " + this.toSeq().map(this.__toStringMapper).join(", ") + " " + t }, concat: function () { return mn(this, sn(this, e.call(arguments, 0))) }, includes: function (e) { return this.some((function (t) { return ge(t, e) })) }, entries: function () { return this.__iterator(R) }, every: function (e, t) { Ve(this.size); var n = !0; return this.__iterate((function (r, o, a) { if (!e.call(t, r, o, a)) return n = !1, !1 })), n }, filter: function (e, t) { return mn(this, en(this, e, t, !0)) }, find: function (e, t, n) { var r = this.findEntry(e, t); return r ? r[1] : n }, forEach: function (e, t) { return Ve(this.size), this.__iterate(t ? e.bind(t) : e) }, join: function (e) { Ve(this.size), e = void 0 !== e ? "" + e : ","; var t = "", n = !0; return this.__iterate((function (r) { n ? n = !1 : t += e, t += null != r ? r.toString() : "" })), t }, keys: function () { return this.__iterator(N) }, map: function (e, t) { return mn(this, Xt(this, e, t)) }, reduce: function (e, t, n) { var r, o; return Ve(this.size), arguments.length < 2 ? o = !0 : r = t, this.__iterate((function (t, a, i) { o ? (o = !1, r = t) : r = e.call(n, r, t, a, i) })), r }, reduceRight: function (e, t, n) { var r = this.toKeyedSeq().reverse(); return r.reduce.apply(r, arguments) }, reverse: function () { return mn(this, Qt(this, !0)) }, slice: function (e, t) { return mn(this, rn(this, e, t, !0)) }, some: function (e, t) { return !this.every(tr(e), t) }, sort: function (e) { return mn(this, pn(this, e)) }, values: function () { return this.__iterator(M) }, butLast: function () { return this.slice(0, -1) }, isEmpty: function () { return void 0 !== this.size ? 0 === this.size : !this.some((function () { return !0 })) }, count: function (e, t) { return A(e ? this.toSeq().filter(e, t) : this) }, countBy: function (e, t) { return tn(this, e, t) }, equals: function (e) { return ye(this, e) }, entrySeq: function () { var e = this; if (e._cache) return new te(e._cache); var t = e.toSeq().map(er).toIndexedSeq(); return t.fromEntrySeq = function () { return e.toSeq() }, t }, filterNot: function (e, t) { return this.filter(tr(e), t) }, findEntry: function (e, t, n) { var r = n; return this.__iterate((function (n, o, a) { if (e.call(t, n, o, a)) return r = [o, n], !1 })), r }, findKey: function (e, t) { var n = this.findEntry(e, t); return n && n[0] }, findLast: function (e, t, n) { return this.toKeyedSeq().reverse().find(e, t, n) }, findLastEntry: function (e, t, n) { return this.toKeyedSeq().reverse().findEntry(e, t, n) }, findLastKey: function (e, t) { return this.toKeyedSeq().reverse().findKey(e, t) }, first: function () { return this.find(O) }, flatMap: function (e, t) { return mn(this, cn(this, e, t)) }, flatten: function (e) { return mn(this, un(this, e, !0)) }, fromEntrySeq: function () { return new Gt(this) }, get: function (e, t) { return this.find((function (t, n) { return ge(n, e) }), void 0, t) }, getIn: function (e, t) { for (var n, r = this, o = xn(e); !(n = o.next()).done;) { var a = n.value; if ((r = r && r.get ? r.get(a, b) : b) === b) return t } return r }, groupBy: function (e, t) { return nn(this, e, t) }, has: function (e) { return this.get(e, b) !== b }, hasIn: function (e) { return this.getIn(e, b) !== b }, isSubset: function (e) { return e = "function" == typeof e.includes ? e : n(e), this.every((function (t) { return e.includes(t) })) }, isSuperset: function (e) { return (e = "function" == typeof e.isSubset ? e : n(e)).isSubset(this) }, keyOf: function (e) { return this.findKey((function (t) { return ge(t, e) })) }, keySeq: function () { return this.toSeq().map(Qn).toIndexedSeq() }, last: function () { return this.toSeq().reverse().first() }, lastKeyOf: function (e) { return this.toKeyedSeq().reverse().keyOf(e) }, max: function (e) { return fn(this, e) }, maxBy: function (e, t) { return fn(this, t, e) }, min: function (e) { return fn(this, e ? nr(e) : ar) }, minBy: function (e, t) { return fn(this, t ? nr(t) : ar, e) }, rest: function () { return this.slice(1) }, skip: function (e) { return this.slice(Math.max(0, e)) }, skipLast: function (e) { return mn(this, this.toSeq().reverse().skip(e).reverse()) }, skipWhile: function (e, t) { return mn(this, an(this, e, t, !0)) }, skipUntil: function (e, t) { return this.skipWhile(tr(e), t) }, sortBy: function (e, t) { return mn(this, pn(this, t, e)) }, take: function (e) { return this.slice(0, Math.max(0, e)) }, takeLast: function (e) { return mn(this, this.toSeq().reverse().take(e).reverse()) }, takeWhile: function (e, t) { return mn(this, on(this, e, t)) }, takeUntil: function (e, t) { return this.takeWhile(tr(e), t) }, valueSeq: function () { return this.toIndexedSeq() }, hashCode: function () { return this.__hash || (this.__hash = ir(this)) } }); var Zn = n.prototype; Zn[p] = !0, Zn[B] = Zn.values, Zn.__toJS = Zn.toArray, Zn.__toStringMapper = rr, Zn.inspect = Zn.toSource = function () { return this.toString() }, Zn.chain = Zn.flatMap, Zn.contains = Zn.includes, Gn(r, { flip: function () { return mn(this, Zt(this)) }, mapEntries: function (e, t) { var n = this, r = 0; return mn(this, this.toSeq().map((function (o, a) { return e.call(t, [a, o], r++, n) })).fromEntrySeq()) }, mapKeys: function (e, t) { var n = this; return mn(this, this.toSeq().flip().map((function (r, o) { return e.call(t, r, o, n) })).flip()) } }); var Xn = r.prototype; function Qn(e, t) { return t } function er(e, t) { return [t, e] } function tr(e) { return function () { return !e.apply(this, arguments) } } function nr(e) { return function () { return -e.apply(this, arguments) } } function rr(e) { return "string" == typeof e ? JSON.stringify(e) : String(e) } function or() { return C(arguments) } function ar(e, t) { return e < t ? 1 : e > t ? -1 : 0 } function ir(e) { if (e.size === 1 / 0) return 0; var t = l(e), n = s(e), r = t ? 1 : 0; return sr(e.__iterate(n ? t ? function (e, t) { r = 31 * r + ur(Oe(e), Oe(t)) | 0 } : function (e, t) { r = r + ur(Oe(e), Oe(t)) | 0 } : t ? function (e) { r = 31 * r + Oe(e) | 0 } : function (e) { r = r + Oe(e) | 0 }), r) } function sr(e, t) { return t = Ae(t, 3432918353), t = Ae(t << 15 | t >>> -15, 461845907), t = Ae(t << 13 | t >>> -13, 5), t = Ae((t = (t + 3864292196 | 0) ^ e) ^ t >>> 16, 2246822507), t = ke((t = Ae(t ^ t >>> 13, 3266489909)) ^ t >>> 16) } function ur(e, t) { return e ^ t + 2654435769 + (e << 6) + (e >> 2) | 0 } return Xn[f] = !0, Xn[B] = Zn.entries, Xn.__toJS = Zn.toObject, Xn.__toStringMapper = function (e, t) { return JSON.stringify(t) + ": " + rr(e) }, Gn(o, { toKeyedSeq: function () { return new $t(this, !1) }, filter: function (e, t) { return mn(this, en(this, e, t, !1)) }, findIndex: function (e, t) { var n = this.findEntry(e, t); return n ? n[0] : -1 }, indexOf: function (e) { var t = this.keyOf(e); return void 0 === t ? -1 : t }, lastIndexOf: function (e) { var t = this.lastKeyOf(e); return void 0 === t ? -1 : t }, reverse: function () { return mn(this, Qt(this, !1)) }, slice: function (e, t) { return mn(this, rn(this, e, t, !1)) }, splice: function (e, t) { var n = arguments.length; if (t = Math.max(0 | t, 0), 0 === n || 2 === n && !t) return this; e = T(e, e < 0 ? this.count() : this.size); var r = this.slice(0, e); return mn(this, 1 === n ? r : r.concat(C(arguments, 2), this.slice(e + t))) }, findLastIndex: function (e, t) { var n = this.findLastEntry(e, t); return n ? n[0] : -1 }, first: function () { return this.get(0) }, flatten: function (e) { return mn(this, un(this, e, !1)) }, get: function (e, t) { return (e = k(this, e)) < 0 || this.size === 1 / 0 || void 0 !== this.size && e > this.size ? t : this.find((function (t, n) { return n === e }), void 0, t) }, has: function (e) { return (e = k(this, e)) >= 0 && (void 0 !== this.size ? this.size === 1 / 0 || e < this.size : -1 !== this.indexOf(e)) }, interpose: function (e) { return mn(this, ln(this, e)) }, interleave: function () { var e = [this].concat(C(arguments)), t = dn(this.toSeq(), Y.of, e), n = t.flatten(!0); return t.size && (n.size = t.size * e.length), mn(this, n) }, keySeq: function () { return we(0, this.size) }, last: function () { return this.get(-1) }, skipWhile: function (e, t) { return mn(this, an(this, e, t, !1)) }, zip: function () { return mn(this, dn(this, or, [this].concat(C(arguments)))) }, zipWith: function (e) { var t = C(arguments); return t[0] = this, mn(this, dn(this, e, t)) } }), o.prototype[h] = !0, o.prototype[d] = !0, Gn(a, { get: function (e, t) { return this.has(e) ? e : t }, includes: function (e) { return this.has(e) }, keySeq: function () { return this.valueSeq() } }), a.prototype.has = Zn.includes, a.prototype.contains = a.prototype.includes, Gn(K, r.prototype), Gn(Y, o.prototype), Gn(G, a.prototype), Gn(Ee, r.prototype), Gn(Se, o.prototype), Gn(Ce, a.prototype), { Iterable: n, Seq: $, Collection: xe, Map: We, OrderedMap: zt, List: St, Stack: Vn, Set: jn, OrderedSet: Ln, Record: En, Range: we, Repeat: be, is: ge, fromJS: he } }() }, function (e, t, n) { e.exports = n(589) }, function (e, t, n) { var r = n(244); e.exports = function (e, t, n) { return t in e ? r(e, t, { value: n, enumerable: !0, configurable: !0, writable: !0 }) : e[t] = n, e } }, function (e, t, n) { e.exports = n(594) }, function (e, t, n) { "use strict"; (function (e) { n.d(t, "t", (function () { return be })), n.d(t, "A", (function () { return _e })), n.d(t, "i", (function () { return we })), n.d(t, "w", (function () { return xe })), n.d(t, "r", (function () { return Ee })), n.d(t, "u", (function () { return Se })), n.d(t, "s", (function () { return Ce })), n.d(t, "p", (function () { return Ae })), n.d(t, "v", (function () { return ke })), n.d(t, "y", (function () { return Oe })), n.d(t, "z", (function () { return je })), n.d(t, "K", (function () { return Te })), n.d(t, "f", (function () { return Ie })), n.d(t, "n", (function () { return Pe })), n.d(t, "h", (function () { return Ne })), n.d(t, "E", (function () { return Me })), n.d(t, "L", (function () { return De })), n.d(t, "o", (function () { return ze })), n.d(t, "D", (function () { return Ve })), n.d(t, "a", (function () { return We })), n.d(t, "I", (function () { return He })), n.d(t, "b", (function () { return Je })), n.d(t, "H", (function () { return $e })), n.d(t, "G", (function () { return Ke })), n.d(t, "F", (function () { return Ye })), n.d(t, "k", (function () { return Ge })), n.d(t, "d", (function () { return Ze })), n.d(t, "g", (function () { return Xe })), n.d(t, "m", (function () { return Qe })), n.d(t, "l", (function () { return et })), n.d(t, "e", (function () { return tt })), n.d(t, "J", (function () { return nt })), n.d(t, "x", (function () { return rt })), n.d(t, "B", (function () { return ot })), n.d(t, "C", (function () { return at })), n.d(t, "j", (function () { return it })), n.d(t, "c", (function () { return st })), n.d(t, "q", (function () { return ct })); var r = n(103), o = n.n(r), a = n(173), i = n.n(a), s = n(67), u = n.n(s), c = n(14), l = n.n(c), p = n(32), f = n.n(p), h = n(15), d = n.n(h), m = (n(38), n(37)), v = n.n(m), g = n(23), y = n.n(g), b = (n(16), n(212)), _ = n.n(b), w = n(22), x = n.n(w), E = n(21), S = n.n(E), C = (n(30), n(17)), A = n.n(C), k = n(12), O = n.n(k), j = n(18), T = n.n(j), I = n(2), P = n.n(I), N = n(51), M = n.n(N), R = n(86), D = n.n(R), L = n(4), B = n.n(L), F = n(13), U = n.n(F), q = n(19), z = n.n(q), V = n(1), W = n.n(V), H = n(514), J = n(515), $ = n.n(J), K = n(286), Y = n.n(K), G = n(287), Z = n.n(G), X = n(213), Q = n.n(X), ee = n(344), te = n.n(ee), ne = n(125), re = n.n(ne), oe = n(66), ae = n.n(oe), ie = n(144), se = n(27), ue = n(517), ce = n.n(ue), le = n(146), pe = n(518), fe = n.n(pe), he = n(519), de = n.n(he), me = n(78), ve = n.n(me), ge = "default", ye = function (e) { return W.a.Iterable.isIterable(e) }; function be(e) { try { var t = JSON.parse(e); if (t && "object" === z()(t)) return t } catch (e) { } return !1 } function _e(e) { return Se(e) ? ye(e) ? e.toJS() : e : {} } function we(e) { var t, n; if (ye(e)) return e; if (e instanceof se.a.File) return e; if (!Se(e)) return e; if (U()(e)) return B()(n = W.a.Seq(e)).call(n, we).toList(); if (ae()(D()(e))) { var r, o = function (e) { if (!ae()(D()(e))) return e; var t, n = {}, r = "_**[]", o = {}, a = M()(D()(e).call(e)); try { for (a.s(); !(t = a.n()).done;) { var i = t.value; if (n[i[0]] || o[i[0]] && o[i[0]].containsMultiple) { var s, u, c, l; if (!o[i[0]]) o[i[0]] = { containsMultiple: !0, length: 1 }, n[P()(c = P()(l = "".concat(i[0])).call(l, r)).call(c, o[i[0]].length)] = n[i[0]], delete n[i[0]]; o[i[0]].length += 1, n[P()(s = P()(u = "".concat(i[0])).call(u, r)).call(s, o[i[0]].length)] = i[1] } else n[i[0]] = i[1] } } catch (e) { a.e(e) } finally { a.f() } return n }(e); return B()(r = W.a.OrderedMap(o)).call(r, we) } return B()(t = W.a.OrderedMap(e)).call(t, we) } function xe(e) { return U()(e) ? e : [e] } function Ee(e) { return "function" == typeof e } function Se(e) { return !!e && "object" === z()(e) } function Ce(e) { return "function" == typeof e } function Ae(e) { return U()(e) } var ke = Z.a; function Oe(e, t) { var n; return S()(n = A()(e)).call(n, (function (n, r) { return n[r] = t(e[r], r), n }), {}) } function je(e, t) { var n; return S()(n = A()(e)).call(n, (function (n, r) { var o = t(e[r], r); return o && "object" === z()(o) && x()(n, o), n }), {}) } function Te(e) { return function (t) { t.dispatch, t.getState; return function (t) { return function (n) { return "function" == typeof n ? n(e()) : t(n) } } } } function Ie(e) { var t, n = e.keySeq(); return n.contains(ge) ? ge : _()(t = O()(n).call(n, (function (e) { return "2" === (e + "")[0] }))).call(t).first() } function Pe(e, t) { if (!W.a.Iterable.isIterable(e)) return W.a.List(); var n = e.getIn(U()(t) ? t : [t]); return W.a.List.isList(n) ? n : W.a.List() } function Ne(e) { var t, n = [/filename\*=[^']+'\w*'"([^"]+)";?/i, /filename\*=[^']+'\w*'([^;]+);?/i, /filename="([^;]*);?"/i, /filename=([^;]*);?/i]; if (v()(n).call(n, (function (n) { return null !== (t = n.exec(e)) })), null !== t && t.length > 1) try { return decodeURIComponent(t[1]) } catch (e) { console.error(e) } return null } function Me(e) { return t = e.replace(/\.[^./]*$/, ""), Y()($()(t)); var t } function Re(e, t, n, r, o) { if (!t) return []; var a = [], i = t.get("nullable"), s = t.get("required"), u = t.get("maximum"), c = t.get("minimum"), l = t.get("type"), p = t.get("format"), f = t.get("maxLength"), h = t.get("minLength"), m = t.get("uniqueItems"), g = t.get("maxItems"), y = t.get("minItems"), b = t.get("pattern"); if (i && null === e) return []; if (l && (n || s || void 0 !== e || "array" === l)) { var _ = "string" === l && e, w = "array" === l && U()(e) && e.length, x = "array" === l && W.a.List.isList(e) && e.count(), E = [_, w, x, "array" === l && "string" == typeof e && e, "file" === l && e instanceof se.a.File, "boolean" === l && (e || !1 === e), "number" === l && (e || 0 === e), "integer" === l && (e || 0 === e), "object" === l && "object" === z()(e) && null !== e, "object" === l && "string" == typeof e && e], S = v()(E).call(E, (function (e) { return !!e })); if ((n || s) && !S && !r) return a.push("Required field is not provided"), a; if ("object" === l && (null === o || "application/json" === o)) { var C, A = e; if ("string" == typeof e) try { A = JSON.parse(e) } catch (e) { return a.push("Parameter string value must be valid JSON"), a } if (t && t.has("required") && Ce(s.isList) && s.isList() && T()(s).call(s, (function (e) { void 0 === A[e] && a.push({ propKey: e, error: "Required property not found" }) })), t && t.has("properties")) T()(C = t.get("properties")).call(C, (function (e, t) { var n = Re(A[t], e, !1, r, o); a.push.apply(a, d()(B()(n).call(n, (function (e) { return { propKey: t, error: e } })))) })) } if (b) { var k = function (e, t) { if (!new RegExp(t).test(e)) return "Value must follow pattern " + t }(e, b); k && a.push(k) } if (y && "array" === l) { var j = function (e, t) { var n; if (!e && t >= 1 || e && e.length < t) return P()(n = "Array must contain at least ".concat(t, " item")).call(n, 1 === t ? "" : "s") }(e, y); j && a.push(j) } if (g && "array" === l) { var I = function (e, t) { var n; if (e && e.length > t) return P()(n = "Array must not contain more then ".concat(t, " item")).call(n, 1 === t ? "" : "s") }(e, g); I && a.push({ needRemove: !0, error: I }) } if (m && "array" === l) { var N = function (e, t) { if (e && ("true" === t || !0 === t)) { var n = Object(V.fromJS)(e), r = n.toSet(); if (e.length > r.size) { var o = Object(V.Set)(); if (T()(n).call(n, (function (e, t) { O()(n).call(n, (function (t) { return Ce(t.equals) ? t.equals(e) : t === e })).size > 1 && (o = o.add(t)) })), 0 !== o.size) return B()(o).call(o, (function (e) { return { index: e, error: "No duplicates allowed." } })).toArray() } } }(e, m); N && a.push.apply(a, d()(N)) } if (f || 0 === f) { var M = function (e, t) { var n; if (e.length > t) return P()(n = "Value must be no longer than ".concat(t, " character")).call(n, 1 !== t ? "s" : "") }(e, f); M && a.push(M) } if (h) { var R = function (e, t) { var n; if (e.length < t) return P()(n = "Value must be at least ".concat(t, " character")).call(n, 1 !== t ? "s" : "") }(e, h); R && a.push(R) } if (u || 0 === u) { var D = function (e, t) { if (e > t) return "Value must be less than ".concat(t) }(e, u); D && a.push(D) } if (c || 0 === c) { var L = function (e, t) { if (e < t) return "Value must be greater than ".concat(t) }(e, c); L && a.push(L) } if ("string" === l) { var F; if (!(F = "date-time" === p ? function (e) { if (isNaN(Date.parse(e))) return "Value must be a DateTime" }(e) : "uuid" === p ? function (e) { if (e = e.toString().toLowerCase(), !/^[{(]?[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}[)}]?$/.test(e)) return "Value must be a Guid" }(e) : function (e) { if (e && "string" != typeof e) return "Value must be a string" }(e))) return a; a.push(F) } else if ("boolean" === l) { var q = function (e) { if ("true" !== e && "false" !== e && !0 !== e && !1 !== e) return "Value must be a boolean" }(e); if (!q) return a; a.push(q) } else if ("number" === l) { var H = function (e) { if (!/^-?\d+(\.?\d+)?$/.test(e)) return "Value must be a number" }(e); if (!H) return a; a.push(H) } else if ("integer" === l) { var J = function (e) { if (!/^-?\d+$/.test(e)) return "Value must be an integer" }(e); if (!J) return a; a.push(J) } else if ("array" === l) { if (!w && !x) return a; e && T()(e).call(e, (function (e, n) { var i = Re(e, t.get("items"), !1, r, o); a.push.apply(a, d()(B()(i).call(i, (function (e) { return { index: n, error: e } })))) })) } else if ("file" === l) { var $ = function (e) { if (e && !(e instanceof se.a.File)) return "Value must be a file" }(e); if (!$) return a; a.push($) } } return a } var De = function (e, t) { var n = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : {}, r = n.isOAS3, o = void 0 !== r && r, a = n.bypassRequiredCheck, i = void 0 !== a && a, s = e.get("required"), u = Object(le.a)(e, { isOAS3: o }), c = u.schema, l = u.parameterContentMediaType; return Re(t, c, s, i, l) }, Le = function (e, t, n) { if (e && (!e.xml || !e.xml.name)) { if (e.xml = e.xml || {}, !e.$$ref) return e.type || e.items || e.properties || e.additionalProperties ? '\n\x3c!-- XML example cannot be generated; root element name is undefined --\x3e' : null; var r = e.$$ref.match(/\S*\/(\S+)$/); e.xml.name = r[1] } return Object(ie.memoizedCreateXMLExample)(e, t, n) }, Be = [{ when: /json/, shouldStringifyTypes: ["string"] }], Fe = ["object"], Ue = function (e, t, n, r) { var o = Object(ie.memoizedSampleFromSchema)(e, t, r), a = z()(o), i = S()(Be).call(Be, (function (e, t) { var r; return t.when.test(n) ? P()(r = []).call(r, d()(e), d()(t.shouldStringifyTypes)) : e }), Fe); return te()(i, (function (e) { return e === a })) ? f()(o, null, 2) : o }, qe = function (e, t, n, r) { var o, a = Ue(e, t, n, r); try { "\n" === (o = ve.a.safeDump(ve.a.safeLoad(a), { lineWidth: -1 }))[o.length - 1] && (o = y()(o).call(o, 0, o.length - 1)) } catch (e) { return console.error(e), "error: could not generate yaml example" } return o.replace(/\t/g, " ") }, ze = function (e) { var t = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : "", n = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : {}, r = arguments.length > 3 && void 0 !== arguments[3] ? arguments[3] : void 0; return e && Ce(e.toJS) && (e = e.toJS()), r && Ce(r.toJS) && (r = r.toJS()), /xml/.test(t) ? Le(e, n, r) : /(yaml|yml)/.test(t) ? qe(e, n, t, r) : Ue(e, n, t, r) }, Ve = function () { var e = {}, t = se.a.location.search; if (!t) return {}; if ("" != t) { var n = t.substr(1).split("&"); for (var r in n) n.hasOwnProperty(r) && (r = n[r].split("="), e[decodeURIComponent(r[0])] = r[1] && decodeURIComponent(r[1]) || "") } return e }, We = function (t) { return (t instanceof e ? t : e.from(t.toString(), "utf-8")).toString("base64") }, He = { operationsSorter: { alpha: function (e, t) { return e.get("path").localeCompare(t.get("path")) }, method: function (e, t) { return e.get("method").localeCompare(t.get("method")) } }, tagsSorter: { alpha: function (e, t) { return e.localeCompare(t) } } }, Je = function (e) { var t = []; for (var n in e) { var r = e[n]; void 0 !== r && "" !== r && t.push([n, "=", encodeURIComponent(r).replace(/%20/g, "+")].join("")) } return t.join("&") }, $e = function (e, t, n) { return !!Q()(n, (function (n) { return re()(e[n], t[n]) })) }; function Ke(e) { return "string" != typeof e || "" === e ? "" : Object(H.sanitizeUrl)(e) } function Ye(e) { return !(!e || l()(e).call(e, "localhost") >= 0 || l()(e).call(e, "127.0.0.1") >= 0 || "none" === e) } function Ge(e) { if (!W.a.OrderedMap.isOrderedMap(e)) return null; if (!e.size) return null; var t = u()(e).call(e, (function (e, t) { return i()(t).call(t, "2") && A()(e.get("content") || {}).length > 0 })), n = e.get("default") || W.a.OrderedMap(), r = (n.get("content") || W.a.OrderedMap()).keySeq().toJS().length ? n : null; return t || r } var Ze = function (e) { return "string" == typeof e || e instanceof String ? o()(e).call(e).replace(/\s/g, "%20") : "" }, Xe = function (e) { return ce()(Ze(e).replace(/%20/g, "_")) }, Qe = function (e) { return O()(e).call(e, (function (e, t) { return /^x-/.test(t) })) }, et = function (e) { return O()(e).call(e, (function (e, t) { return /^pattern|maxLength|minLength|maximum|minimum/.test(t) })) }; function tt(e, t) { var n, r = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : function () { return !0 }; if ("object" !== z()(e) || U()(e) || null === e || !t) return e; var o = x()({}, e); return T()(n = A()(o)).call(n, (function (e) { e === t && r(o[e], e) ? delete o[e] : o[e] = tt(o[e], t, r) })), o } function nt(e) { if ("string" == typeof e) return e; if (e && e.toJS && (e = e.toJS()), "object" === z()(e) && null !== e) try { return f()(e, null, 2) } catch (t) { return String(e) } return null == e ? "" : e.toString() } function rt(e) { return "number" == typeof e ? e.toString() : e } function ot(e) { var t = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}, n = t.returnAll, r = void 0 !== n && n, o = t.allowHashes, a = void 0 === o || o; if (!W.a.Map.isMap(e)) throw new Error("paramToIdentifier: received a non-Im.Map parameter as input"); var i, s, u, c = e.get("name"), l = e.get("in"), p = []; e && e.hashCode && l && c && a && p.push(P()(i = P()(s = "".concat(l, ".")).call(s, c, ".hash-")).call(i, e.hashCode())); l && c && p.push(P()(u = "".concat(l, ".")).call(u, c)); return p.push(c), r ? p : p[0] || "" } function at(e, t) { var n, r = ot(e, { returnAll: !0 }); return O()(n = B()(r).call(r, (function (e) { return t[e] }))).call(n, (function (e) { return void 0 !== e }))[0] } function it() { return ut(fe()(32).toString("base64")) } function st(e) { return ut(de()("sha256").update(e).digest("base64")) } function ut(e) { return e.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "") } var ct = function (e) { return !e || !(!ye(e) || !e.isEmpty()) } }).call(this, n(77).Buffer) }, function (e, t) { e.exports = function (e, t) { if (!(e instanceof t)) throw new TypeError("Cannot call a class as a function") } }, function (e, t, n) { var r = n(244); function o(e, t) { for (var n = 0; n < t.length; n++) { var o = t[n]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), r(e, o.key, o) } } e.exports = function (e, t, n) { return t && o(e.prototype, t), n && o(e, n), e } }, function (e, t, n) { var r = n(920), o = n(923); e.exports = function (e, t) { if ("function" != typeof t && null !== t) throw new TypeError("Super expression must either be null or a function"); e.prototype = r(t && t.prototype, { constructor: { value: e, writable: !0, configurable: !0 } }), t && o(e, t) } }, function (e, t, n) { var r = n(470), o = n(210), a = n(934), i = n(935); e.exports = function (e) { var t = a(); return function () { var n, a = o(e); if (t) { var s = o(this).constructor; n = r(a, arguments, s) } else n = a.apply(this, arguments); return i(this, n) } } }, function (e, t) { e.exports = function (e) { if (void 0 === e) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); return e } }, function (e, t, n) { e.exports = n(1013)() }, function (e, t, n) { e.exports = n(586) }, function (e, t, n) { e.exports = n(603) }, function (e, t, n) { e.exports = n(651) }, function (e, t, n) { var r = n(654), o = n(393), a = n(186), i = n(663); e.exports = function (e) { return r(e) || o(e) || a(e) || i() } }, function (e, t, n) { var r = n(401), o = n(674), a = n(186), i = n(404); e.exports = function (e, t) { return r(e) || o(e, t) || a(e, t) || i() } }, function (e, t, n) { e.exports = n(553) }, function (e, t, n) { e.exports = n(405) }, function (e, t, n) { var r = n(555), o = n(181); function a(t) { return e.exports = a = "function" == typeof o && "symbol" == typeof r ? function (e) { return typeof e } : function (e) { return e && "function" == typeof o && e.constructor === o && e !== o.prototype ? "symbol" : typeof e }, a(t) } e.exports = a }, function (e, t, n) { "use strict"; function r(e, t) { return e === t } function o(e, t, n) { if (null === t || null === n || t.length !== n.length) return !1; for (var r = t.length, o = 0; o < r; o++)if (!e(t[o], n[o])) return !1; return !0 } function a(e) { var t = Array.isArray(e[0]) ? e[0] : e; if (!t.every((function (e) { return "function" == typeof e }))) { var n = t.map((function (e) { return typeof e })).join(", "); throw new Error("Selector creators expect all input-selectors to be functions, instead received the following types: [" + n + "]") } return t } n.d(t, "a", (function () { return i })); var i = function (e) { for (var t = arguments.length, n = Array(t > 1 ? t - 1 : 0), r = 1; r < t; r++)n[r - 1] = arguments[r]; return function () { for (var t = arguments.length, r = Array(t), o = 0; o < t; o++)r[o] = arguments[o]; var i = 0, s = r.pop(), u = a(r), c = e.apply(void 0, [function () { return i++, s.apply(null, arguments) }].concat(n)), l = e((function () { for (var e = [], t = u.length, n = 0; n < t; n++)e.push(u[n].apply(null, arguments)); return c.apply(null, e) })); return l.resultFunc = s, l.dependencies = u, l.recomputations = function () { return i }, l.resetRecomputations = function () { return i = 0 }, l } }((function (e) { var t = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : r, n = null, a = null; return function () { return o(t, n, arguments) || (a = e.apply(null, arguments)), n = arguments, a } })) }, function (e, t, n) { e.exports = n(598) }, function (e, t, n) { e.exports = n(610) }, function (e, t, n) { e.exports = n(607) }, function (e, t, n) { "use strict"; var r = n(42), o = n(107).f, a = n(358), i = n(33), s = n(109), u = n(70), c = n(52), l = function (e) { var t = function (t, n, r) { if (this instanceof e) { switch (arguments.length) { case 0: return new e; case 1: return new e(t); case 2: return new e(t, n) }return new e(t, n, r) } return e.apply(this, arguments) }; return t.prototype = e.prototype, t }; e.exports = function (e, t) { var n, p, f, h, d, m, v, g, y = e.target, b = e.global, _ = e.stat, w = e.proto, x = b ? r : _ ? r[y] : (r[y] || {}).prototype, E = b ? i : i[y] || (i[y] = {}), S = E.prototype; for (f in t) n = !a(b ? f : y + (_ ? "." : "#") + f, e.forced) && x && c(x, f), d = E[f], n && (m = e.noTargetGet ? (g = o(x, f)) && g.value : x[f]), h = n && m ? m : t[f], n && typeof d == typeof h || (v = e.bind && n ? s(h, r) : e.wrap && n ? l(h) : w && "function" == typeof h ? s(Function.call, h) : h, (e.sham || h && h.sham || d && d.sham) && u(v, "sham", !0), E[f] = v, w && (c(i, p = y + "Prototype") || u(i, p, {}), i[p][f] = h, e.real && S && !S[f] && u(S, f, h))) } }, function (e, t, n) { var r = n(244), o = n(874), a = n(878), i = n(883), s = n(450), u = n(888), c = n(451), l = n(452), p = n(3); function f(e, t) { var n = l(e); if (c) { var r = c(e); t && (r = u(r).call(r, (function (t) { return s(e, t).enumerable }))), n.push.apply(n, r) } return n } e.exports = function (e) { for (var t = 1; t < arguments.length; t++) { var n, u = null != arguments[t] ? arguments[t] : {}; if (t % 2) i(n = f(Object(u), !0)).call(n, (function (t) { p(e, t, u[t]) })); else if (a) o(e, a(u)); else { var c; i(c = f(Object(u))).call(c, (function (t) { r(e, t, s(u, t)) })) } } return e } }, function (e, t, n) { "use strict"; e.exports = function (e, t, n, r, o, a, i, s) { if (!e) { var u; if (void 0 === t) u = new Error("Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings."); else { var c = [n, r, o, a, i, s], l = 0; (u = new Error(t.replace(/%s/g, (function () { return c[l++] })))).name = "Invariant Violation" } throw u.framesToPop = 1, u } } }, function (e, t, n) { "use strict"; t.a = function () { var e = { location: {}, history: {}, open: function () { }, close: function () { }, File: function () { } }; if ("undefined" == typeof window) return e; try { e = window; for (var t = 0, n = ["File", "Blob", "FormData"]; t < n.length; t++) { var r = n[t]; r in window && (e[r] = window[r]) } } catch (e) { console.error(e) } return e }() }, function (e, t, n) { "use strict"; var r, o = n(1), a = "<>", i = function () { invariant(!1, "ImmutablePropTypes type checking code is stripped in production.") }; i.isRequired = i; var s = function () { return i }; function u(e) { var t = typeof e; return Array.isArray(e) ? "array" : e instanceof RegExp ? "object" : e instanceof o.Iterable ? "Immutable." + e.toSource().split(" ")[0] : t } function c(e) { function t(t, n, r, o, i, s) { for (var u = arguments.length, c = Array(u > 6 ? u - 6 : 0), l = 6; l < u; l++)c[l - 6] = arguments[l]; if (s = s || r, o = o || a, null != n[r]) return e.apply(void 0, [n, r, o, i, s].concat(c)); var p = i; return t ? new Error("Required " + p + " `" + s + "` was not specified in `" + o + "`.") : void 0 } var n = t.bind(null, !1); return n.isRequired = t.bind(null, !0), n } function l(e, t) { return n = "Iterable." + e, r = function (e) { return o.Iterable.isIterable(e) && t(e) }, c((function (e, t, o, a, i) { var s = e[t]; if (!r(s)) { var c = u(s); return new Error("Invalid " + a + " `" + i + "` of type `" + c + "` supplied to `" + o + "`, expected `" + n + "`.") } return null })); var n, r } (r = { listOf: s, mapOf: s, orderedMapOf: s, setOf: s, orderedSetOf: s, stackOf: s, iterableOf: s, recordOf: s, shape: s, contains: s, mapContains: s, orderedMapContains: s, list: i, map: i, orderedMap: i, set: i, orderedSet: i, stack: i, seq: i, record: i, iterable: i }).iterable.indexed = l("Indexed", o.Iterable.isIndexed), r.iterable.keyed = l("Keyed", o.Iterable.isKeyed), e.exports = r }, function (e, t, n) { var r = n(918); function o() { return e.exports = o = r || function (e) { for (var t = 1; t < arguments.length; t++) { var n = arguments[t]; for (var r in n) Object.prototype.hasOwnProperty.call(n, r) && (e[r] = n[r]) } return e }, o.apply(this, arguments) } e.exports = o }, function (e, t, n) { e.exports = n(612) }, function (e, t, n) { "use strict"; e.exports = function (e) { for (var t = arguments.length - 1, n = "Minified React error #" + e + "; visit http://facebook.github.io/react/docs/error-decoder.html?invariant=" + e, r = 0; r < t; r++)n += "&args[]=" + encodeURIComponent(arguments[r + 1]); n += " for the full message or use the non-minified dev environment for full errors and additional helpful warnings."; var o = new Error(n); throw o.name = "Invariant Violation", o.framesToPop = 1, o } }, function (e, t, n) { e.exports = n(550) }, function (e, t) { e.exports = {} }, function (e, t, n) { "use strict"; var r = n(83); e.exports = r }, function (e, t) { e.exports = function (e) { try { return !!e() } catch (e) { return !0 } } }, function (e, t, n) { "use strict"; n.r(t), n.d(t, "isOAS3", (function () { return c })), n.d(t, "isSwagger2", (function () { return l })), n.d(t, "OAS3ComponentWrapFactory", (function () { return p })); var r = n(29), o = n.n(r), a = n(173), i = n.n(a), s = n(0), u = n.n(s); function c(e) { var t = e.get("openapi"); return "string" == typeof t && (i()(t).call(t, "3.0.") && t.length > 4) } function l(e) { var t = e.get("swagger"); return "string" == typeof t && i()(t).call(t, "2.0") } function p(e) { return function (t, n) { return function (r) { return n && n.specSelectors && n.specSelectors.specJson ? c(n.specSelectors.specJson()) ? u.a.createElement(e, o()({}, r, n, { Ori: t })) : u.a.createElement(t, r) : (console.warn("OAS3 wrapper: couldn't get spec"), null) } } } }, function (e, t, n) { e.exports = n(670) }, function (e, t, n) { e.exports = n(664) }, function (e, t, n) { var r = n(42), o = n(233), a = n(52), i = n(179), s = n(235), u = n(362), c = o("wks"), l = r.Symbol, p = u ? l : l && l.withoutSetter || i; e.exports = function (e) { return a(c, e) || (s && a(l, e) ? c[e] = l[e] : c[e] = p("Symbol." + e)), c[e] } }, function (e, t, n) { "use strict"; var r = Object.getOwnPropertySymbols, o = Object.prototype.hasOwnProperty, a = Object.prototype.propertyIsEnumerable; function i(e) { if (null == e) throw new TypeError("Object.assign cannot be called with null or undefined"); return Object(e) } e.exports = function () { try { if (!Object.assign) return !1; var e = new String("abc"); if (e[5] = "de", "5" === Object.getOwnPropertyNames(e)[0]) return !1; for (var t = {}, n = 0; n < 10; n++)t["_" + String.fromCharCode(n)] = n; if ("0123456789" !== Object.getOwnPropertyNames(t).map((function (e) { return t[e] })).join("")) return !1; var r = {}; return "abcdefghijklmnopqrst".split("").forEach((function (e) { r[e] = e })), "abcdefghijklmnopqrst" === Object.keys(Object.assign({}, r)).join("") } catch (e) { return !1 } }() ? Object.assign : function (e, t) { for (var n, s, u = i(e), c = 1; c < arguments.length; c++) { for (var l in n = Object(arguments[c])) o.call(n, l) && (u[l] = n[l]); if (r) { s = r(n); for (var p = 0; p < s.length; p++)a.call(n, s[p]) && (u[s[p]] = n[s[p]]) } } return u } }, function (e, t, n) { e.exports = n(898) }, function (e, t, n) { (function (t) { var n = function (e) { return e && e.Math == Math && e }; e.exports = n("object" == typeof globalThis && globalThis) || n("object" == typeof window && window) || n("object" == typeof self && self) || n("object" == typeof t && t) || function () { return this }() || Function("return this")() }).call(this, n(55)) }, function (e, t, n) { var r = n(33); e.exports = function (e) { return r[e + "Prototype"] } }, function (e, t, n) { "use strict"; var r = n(31), o = n(139), a = n(471), i = (n(26), o.ID_ATTRIBUTE_NAME), s = a, u = "__reactInternalInstance$" + Math.random().toString(36).slice(2); function c(e, t) { return 1 === e.nodeType && e.getAttribute(i) === String(t) || 8 === e.nodeType && e.nodeValue === " react-text: " + t + " " || 8 === e.nodeType && e.nodeValue === " react-empty: " + t + " " } function l(e) { for (var t; t = e._renderedComponent;)e = t; return e } function p(e, t) { var n = l(e); n._hostNode = t, t[u] = n } function f(e, t) { if (!(e._flags & s.hasCachedChildNodes)) { var n = e._renderedChildren, o = t.firstChild; e: for (var a in n) if (n.hasOwnProperty(a)) { var i = n[a], u = l(i)._domID; if (0 !== u) { for (; null !== o; o = o.nextSibling)if (c(o, u)) { p(i, o); continue e } r("32", u) } } e._flags |= s.hasCachedChildNodes } } function h(e) { if (e[u]) return e[u]; for (var t, n, r = []; !e[u];) { if (r.push(e), !e.parentNode) return null; e = e.parentNode } for (; e && (n = e[u]); e = r.pop())t = n, r.length && f(n, e); return t } var d = { getClosestInstanceFromNode: h, getInstanceFromNode: function (e) { var t = h(e); return null != t && t._hostNode === e ? t : null }, getNodeFromInstance: function (e) { if (void 0 === e._hostNode && r("33"), e._hostNode) return e._hostNode; for (var t = []; !e._hostNode;)t.push(e), e._hostParent || r("34"), e = e._hostParent; for (; t.length; e = t.pop())f(e, e._hostNode); return e._hostNode }, precacheChildNodes: f, precacheNode: p, uncacheNode: function (e) { var t = e._hostNode; t && (delete t[u], e._hostNode = null) } }; e.exports = d }, function (e, t) { e.exports = function (e) { return "object" == typeof e ? null !== e : "function" == typeof e } }, function (e, t, n) { var r = n(197); e.exports = function (e, t, n) { var o = null == e ? void 0 : r(e, t); return void 0 === o ? n : o } }, function (e, t, n) { "use strict"; n.r(t), n.d(t, "UPDATE_SPEC", (function () { return te })), n.d(t, "UPDATE_URL", (function () { return ne })), n.d(t, "UPDATE_JSON", (function () { return re })), n.d(t, "UPDATE_PARAM", (function () { return oe })), n.d(t, "UPDATE_EMPTY_PARAM_INCLUSION", (function () { return ae })), n.d(t, "VALIDATE_PARAMS", (function () { return ie })), n.d(t, "SET_RESPONSE", (function () { return se })), n.d(t, "SET_REQUEST", (function () { return ue })), n.d(t, "SET_MUTATED_REQUEST", (function () { return ce })), n.d(t, "LOG_REQUEST", (function () { return le })), n.d(t, "CLEAR_RESPONSE", (function () { return pe })), n.d(t, "CLEAR_REQUEST", (function () { return fe })), n.d(t, "CLEAR_VALIDATE_PARAMS", (function () { return he })), n.d(t, "UPDATE_OPERATION_META_VALUE", (function () { return de })), n.d(t, "UPDATE_RESOLVED", (function () { return me })), n.d(t, "UPDATE_RESOLVED_SUBTREE", (function () { return ve })), n.d(t, "SET_SCHEME", (function () { return ge })), n.d(t, "updateSpec", (function () { return ye })), n.d(t, "updateResolved", (function () { return be })), n.d(t, "updateUrl", (function () { return _e })), n.d(t, "updateJsonSpec", (function () { return we })), n.d(t, "parseToJson", (function () { return xe })), n.d(t, "resolveSpec", (function () { return Se })), n.d(t, "requestResolvedSubtree", (function () { return ke })), n.d(t, "changeParam", (function () { return Oe })), n.d(t, "changeParamByIdentity", (function () { return je })), n.d(t, "updateResolvedSubtree", (function () { return Te })), n.d(t, "invalidateResolvedSubtreeCache", (function () { return Ie })), n.d(t, "validateParams", (function () { return Pe })), n.d(t, "updateEmptyParamInclusion", (function () { return Ne })), n.d(t, "clearValidateParams", (function () { return Me })), n.d(t, "changeConsumesValue", (function () { return Re })), n.d(t, "changeProducesValue", (function () { return De })), n.d(t, "setResponse", (function () { return Le })), n.d(t, "setRequest", (function () { return Be })), n.d(t, "setMutatedRequest", (function () { return Fe })), n.d(t, "logRequest", (function () { return Ue })), n.d(t, "executeRequest", (function () { return qe })), n.d(t, "execute", (function () { return ze })), n.d(t, "clearResponse", (function () { return Ve })), n.d(t, "clearRequest", (function () { return We })), n.d(t, "setScheme", (function () { return He })); var r = n(25), o = n.n(r), a = n(56), i = n.n(a), s = n(346), u = n.n(s), c = n(22), l = n.n(c), p = n(17), f = n.n(p), h = n(2), d = n.n(h), m = n(18), v = n.n(m), g = n(14), y = n.n(g), b = n(41), _ = n.n(b), w = n(214), x = n.n(w), E = n(12), S = n.n(E), C = n(68), A = n.n(C), k = n(104), O = n.n(k), j = n(21), T = n.n(j), I = n(79), P = n.n(I), N = n(347), M = n.n(N), R = n(4), D = n.n(R), L = n(13), B = n.n(L), F = n(19), U = n.n(F), q = n(78), z = n.n(q), V = n(1), W = n(98), H = n.n(W), J = n(143), $ = n.n(J), K = n(215), Y = n.n(K), G = n(521), Z = n.n(G), X = n(348), Q = n.n(X), ee = n(5), te = "spec_update_spec", ne = "spec_update_url", re = "spec_update_json", oe = "spec_update_param", ae = "spec_update_empty_param_inclusion", ie = "spec_validate_param", se = "spec_set_response", ue = "spec_set_request", ce = "spec_set_mutated_request", le = "spec_log_request", pe = "spec_clear_response", fe = "spec_clear_request", he = "spec_clear_validate_param", de = "spec_update_operation_meta_value", me = "spec_update_resolved", ve = "spec_update_resolved_subtree", ge = "set_scheme"; function ye(e) { var t, n = (t = e, Y()(t) ? t : "").replace(/\t/g, " "); if ("string" == typeof e) return { type: te, payload: n } } function be(e) { return { type: me, payload: e } } function _e(e) { return { type: ne, payload: e } } function we(e) { return { type: re, payload: e } } var xe = function (e) { return function (t) { var n = t.specActions, r = t.specSelectors, o = t.errActions, a = r.specStr, i = null; try { e = e || a(), o.clear({ source: "parser" }), i = z.a.safeLoad(e) } catch (e) { return console.error(e), o.newSpecErr({ source: "parser", level: "error", message: e.reason, line: e.mark && e.mark.line ? e.mark.line + 1 : void 0 }) } return i && "object" === U()(i) ? n.updateJsonSpec(i) : {} } }, Ee = !1, Se = function (e, t) { return function (n) { var r = n.specActions, o = n.specSelectors, a = n.errActions, i = n.fn, s = i.fetch, u = i.resolve, c = i.AST, l = void 0 === c ? {} : c, p = n.getConfigs; Ee || (console.warn("specActions.resolveSpec is deprecated since v3.10.0 and will be removed in v4.0.0; use requestResolvedSubtree instead!"), Ee = !0); var f = p(), h = f.modelPropertyMacro, d = f.parameterMacro, m = f.requestInterceptor, v = f.responseInterceptor; void 0 === e && (e = o.specJson()), void 0 === t && (t = o.url()); var g = l.getLineNumberForPath ? l.getLineNumberForPath : function () { }, y = o.specStr(); return u({ fetch: s, spec: e, baseDoc: t, modelPropertyMacro: h, parameterMacro: d, requestInterceptor: m, responseInterceptor: v }).then((function (e) { var t = e.spec, n = e.errors; if (a.clear({ type: "thrown" }), B()(n) && n.length > 0) { var o = D()(n).call(n, (function (e) { return console.error(e), e.line = e.fullPath ? g(y, e.fullPath) : null, e.path = e.fullPath ? e.fullPath.join(".") : null, e.level = "error", e.type = "thrown", e.source = "resolver", M()(e, "message", { enumerable: !0, value: e.message }), e })); a.newThrownErrBatch(o) } return r.updateResolved(t) })) } }, Ce = [], Ae = Z()(P()(_.a.mark((function e() { var t, n, r, o, a, i, s, u, c, l, p, f, h, d, m, v, g, y; return _.a.wrap((function (e) { for (; ;)switch (e.prev = e.next) { case 0: if (t = Ce.system) { e.next = 4; break } return console.error("debResolveSubtrees: don't have a system to operate on, aborting."), e.abrupt("return"); case 4: if (n = t.errActions, r = t.errSelectors, o = t.fn, a = o.resolveSubtree, i = o.fetch, s = o.AST, u = void 0 === s ? {} : s, c = t.specSelectors, l = t.specActions, a) { e.next = 8; break } return console.error("Error: Swagger-Client did not provide a `resolveSubtree` method, doing nothing."), e.abrupt("return"); case 8: return p = u.getLineNumberForPath ? u.getLineNumberForPath : function () { }, f = c.specStr(), h = t.getConfigs(), d = h.modelPropertyMacro, m = h.parameterMacro, v = h.requestInterceptor, g = h.responseInterceptor, e.prev = 11, e.next = 14, T()(Ce).call(Ce, function () { var e = P()(_.a.mark((function e(t, o) { var s, u, l, h, y, b, w, E, C; return _.a.wrap((function (e) { for (; ;)switch (e.prev = e.next) { case 0: return e.next = 2, t; case 2: return s = e.sent, u = s.resultMap, l = s.specWithCurrentSubtrees, e.next = 7, a(l, o, { baseDoc: c.url(), modelPropertyMacro: d, parameterMacro: m, requestInterceptor: v, responseInterceptor: g }); case 7: if (h = e.sent, y = h.errors, b = h.spec, r.allErrors().size && n.clearBy((function (e) { var t; return "thrown" !== e.get("type") || "resolver" !== e.get("source") || !O()(t = e.get("fullPath")).call(t, (function (e, t) { return e === o[t] || void 0 === o[t] })) })), B()(y) && y.length > 0 && (w = D()(y).call(y, (function (e) { return e.line = e.fullPath ? p(f, e.fullPath) : null, e.path = e.fullPath ? e.fullPath.join(".") : null, e.level = "error", e.type = "thrown", e.source = "resolver", M()(e, "message", { enumerable: !0, value: e.message }), e })), n.newThrownErrBatch(w)), !b || !c.isOAS3() || "components" !== o[0] || "securitySchemes" !== o[1]) { e.next = 15; break } return e.next = 15, A.a.all(D()(E = S()(C = x()(b)).call(C, (function (e) { return "openIdConnect" === e.type }))).call(E, function () { var e = P()(_.a.mark((function e(t) { var n, r; return _.a.wrap((function (e) { for (; ;)switch (e.prev = e.next) { case 0: return n = { url: t.openIdConnectUrl, requestInterceptor: v, responseInterceptor: g }, e.prev = 1, e.next = 4, i(n); case 4: (r = e.sent) instanceof Error || r.status >= 400 ? console.error(r.statusText + " " + n.url) : t.openIdConnectData = JSON.parse(r.text), e.next = 11; break; case 8: e.prev = 8, e.t0 = e.catch(1), console.error(e.t0); case 11: case "end": return e.stop() } }), e, null, [[1, 8]]) }))); return function (t) { return e.apply(this, arguments) } }())); case 15: return Q()(u, o, b), Q()(l, o, b), e.abrupt("return", { resultMap: u, specWithCurrentSubtrees: l }); case 18: case "end": return e.stop() } }), e) }))); return function (t, n) { return e.apply(this, arguments) } }(), A.a.resolve({ resultMap: (c.specResolvedSubtree([]) || Object(V.Map)()).toJS(), specWithCurrentSubtrees: c.specJson().toJS() })); case 14: y = e.sent, delete Ce.system, Ce = [], e.next = 22; break; case 19: e.prev = 19, e.t0 = e.catch(11), console.error(e.t0); case 22: l.updateResolvedSubtree([], y.resultMap); case 23: case "end": return e.stop() } }), e, null, [[11, 19]]) }))), 35), ke = function (e) { return function (t) { var n; y()(n = D()(Ce).call(Ce, (function (e) { return e.join("@@") }))).call(n, e.join("@@")) > -1 || (Ce.push(e), Ce.system = t, Ae()) } }; function Oe(e, t, n, r, o) { return { type: oe, payload: { path: e, value: r, paramName: t, paramIn: n, isXml: o } } } function je(e, t, n, r) { return { type: oe, payload: { path: e, param: t, value: n, isXml: r } } } var Te = function (e, t) { return { type: ve, payload: { path: e, value: t } } }, Ie = function () { return { type: ve, payload: { path: [], value: Object(V.Map)() } } }, Pe = function (e, t) { return { type: ie, payload: { pathMethod: e, isOAS3: t } } }, Ne = function (e, t, n, r) { return { type: ae, payload: { pathMethod: e, paramName: t, paramIn: n, includeEmptyValue: r } } }; function Me(e) { return { type: he, payload: { pathMethod: e } } } function Re(e, t) { return { type: de, payload: { path: e, value: t, key: "consumes_value" } } } function De(e, t) { return { type: de, payload: { path: e, value: t, key: "produces_value" } } } var Le = function (e, t, n) { return { payload: { path: e, method: t, res: n }, type: se } }, Be = function (e, t, n) { return { payload: { path: e, method: t, req: n }, type: ue } }, Fe = function (e, t, n) { return { payload: { path: e, method: t, req: n }, type: ce } }, Ue = function (e) { return { payload: e, type: le } }, qe = function (e) { return function (t) { var n, r, o = t.fn, a = t.specActions, i = t.specSelectors, s = t.getConfigs, c = t.oas3Selectors, p = e.pathName, h = e.method, m = e.operation, g = s(), y = g.requestInterceptor, b = g.responseInterceptor, w = m.toJS(); m && m.get("parameters") && v()(n = S()(r = m.get("parameters")).call(r, (function (e) { return e && !0 === e.get("allowEmptyValue") }))).call(n, (function (t) { if (i.parameterInclusionSettingFor([p, h], t.get("name"), t.get("in"))) { e.parameters = e.parameters || {}; var n = Object(ee.C)(t, e.parameters); (!n || n && 0 === n.size) && (e.parameters[t.get("name")] = "") } })); if (e.contextUrl = H()(i.url()).toString(), w && w.operationId ? e.operationId = w.operationId : w && p && h && (e.operationId = o.opId(w, p, h)), i.isOAS3()) { var x, E = d()(x = "".concat(p, ":")).call(x, h); e.server = c.selectedServer(E) || c.selectedServer(); var C = c.serverVariables({ server: e.server, namespace: E }).toJS(), A = c.serverVariables({ server: e.server }).toJS(); e.serverVariables = f()(C).length ? C : A, e.requestContentType = c.requestContentType(p, h), e.responseContentType = c.responseContentType(p, h) || "*/*"; var k = c.requestBodyValue(p, h), O = c.requestBodyInclusionSetting(p, h); if (Object(ee.t)(k)) e.requestBody = JSON.parse(k); else if (k && k.toJS) { var j; e.requestBody = S()(j = D()(k).call(k, (function (e) { return V.Map.isMap(e) ? e.get("value") : e }))).call(j, (function (e, t) { return (B()(e) ? 0 !== e.length : !Object(ee.q)(e)) || O.get(t) })).toJS() } else e.requestBody = k } var T = l()({}, e); T = o.buildRequest(T), a.setRequest(e.pathName, e.method, T); var I = function () { var t = P()(_.a.mark((function t(n) { var r, o; return _.a.wrap((function (t) { for (; ;)switch (t.prev = t.next) { case 0: return t.next = 2, y.apply(undefined, [n]); case 2: return r = t.sent, o = l()({}, r), a.setMutatedRequest(e.pathName, e.method, o), t.abrupt("return", r); case 6: case "end": return t.stop() } }), t) }))); return function (e) { return t.apply(this, arguments) } }(); e.requestInterceptor = I, e.responseInterceptor = b; var N = u()(); return o.execute(e).then((function (t) { t.duration = u()() - N, a.setResponse(e.pathName, e.method, t) })).catch((function (t) { console.error(t), a.setResponse(e.pathName, e.method, { error: !0, err: $()(t) }) })) } }, ze = function () { var e = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, t = e.path, n = e.method, r = i()(e, ["path", "method"]); return function (e) { var a = e.fn.fetch, i = e.specSelectors, s = e.specActions, u = i.specJsonWithResolvedSubtrees().toJS(), c = i.operationScheme(t, n), l = i.contentTypeValues([t, n]).toJS(), p = l.requestContentType, f = l.responseContentType, h = /xml/i.test(p), d = i.parameterValues([t, n], h).toJS(); return s.executeRequest(o()(o()({}, r), {}, { fetch: a, spec: u, pathName: t, method: n, parameters: d, requestContentType: p, scheme: c, responseContentType: f })) } }; function Ve(e, t) { return { type: pe, payload: { path: e, method: t } } } function We(e, t) { return { type: fe, payload: { path: e, method: t } } } function He(e, t, n) { return { type: ge, payload: { scheme: e, path: t, method: n } } } }, function (e, t, n) { var r = n(33), o = n(52), a = n(232), i = n(71).f; e.exports = function (e) { var t = r.Symbol || (r.Symbol = {}); o(t, e) || i(t, e, { value: a.f(e) }) } }, function (e, t, n) { var r = n(35); e.exports = !r((function () { return 7 != Object.defineProperty({}, 1, { get: function () { return 7 } })[1] })) }, function (e, t, n) { "use strict"; var r = n(163), o = ["kind", "resolve", "construct", "instanceOf", "predicate", "represent", "defaultStyle", "styleAliases"], a = ["scalar", "sequence", "mapping"]; e.exports = function (e, t) { var n, i; if (t = t || {}, Object.keys(t).forEach((function (t) { if (-1 === o.indexOf(t)) throw new r('Unknown option "' + t + '" is met in definition of "' + e + '" YAML type.') })), this.tag = e, this.kind = t.kind || null, this.resolve = t.resolve || function () { return !0 }, this.construct = t.construct || function (e) { return e }, this.instanceOf = t.instanceOf || null, this.predicate = t.predicate || null, this.represent = t.represent || null, this.defaultStyle = t.defaultStyle || null, this.styleAliases = (n = t.styleAliases || null, i = {}, null !== n && Object.keys(n).forEach((function (e) { n[e].forEach((function (t) { i[String(t)] = e })) })), i), -1 === a.indexOf(this.kind)) throw new r('Unknown kind "' + this.kind + '" is specified for "' + e + '" YAML type.') } }, function (e, t, n) { var r = n(402), o = n(246), a = n(684), i = n(181), s = n(186); e.exports = function (e, t) { var n; if (void 0 === i || null == a(e)) { if (o(e) || (n = s(e)) || t && e && "number" == typeof e.length) { n && (e = n); var u = 0, c = function () { }; return { s: c, n: function () { return u >= e.length ? { done: !0 } : { done: !1, value: e[u++] } }, e: function (e) { throw e }, f: c } } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.") } var l, p = !0, f = !1; return { s: function () { n = r(e) }, n: function () { var e = n.next(); return p = e.done, e }, e: function (e) { f = !0, l = e }, f: function () { try { p || null == n.return || n.return() } finally { if (f) throw l } } } } }, function (e, t) { var n = {}.hasOwnProperty; e.exports = function (e, t) { return n.call(e, t) } }, function (e, t, n) { var r = n(45); e.exports = function (e) { if (!r(e)) throw TypeError(String(e) + " is not an object"); return e } }, function (e, t) { var n = Array.isArray; e.exports = n }, function (e, t) { var n; n = function () { return this }(); try { n = n || new Function("return this")() } catch (e) { "object" == typeof window && (n = window) } e.exports = n }, function (e, t, n) { var r = n(453), o = n(451), a = n(894); e.exports = function (e, t) { if (null == e) return {}; var n, i, s = a(e, t); if (o) { var u = o(e); for (i = 0; i < u.length; i++)n = u[i], r(t).call(t, n) >= 0 || Object.prototype.propertyIsEnumerable.call(e, n) && (s[n] = e[n]) } return s } }, function (e, t, n) { "use strict"; n.r(t), n.d(t, "UPDATE_SELECTED_SERVER", (function () { return r })), n.d(t, "UPDATE_REQUEST_BODY_VALUE", (function () { return o })), n.d(t, "UPDATE_REQUEST_BODY_VALUE_RETAIN_FLAG", (function () { return a })), n.d(t, "UPDATE_REQUEST_BODY_INCLUSION", (function () { return i })), n.d(t, "UPDATE_ACTIVE_EXAMPLES_MEMBER", (function () { return s })), n.d(t, "UPDATE_REQUEST_CONTENT_TYPE", (function () { return u })), n.d(t, "UPDATE_RESPONSE_CONTENT_TYPE", (function () { return c })), n.d(t, "UPDATE_SERVER_VARIABLE_VALUE", (function () { return l })), n.d(t, "SET_REQUEST_BODY_VALIDATE_ERROR", (function () { return p })), n.d(t, "CLEAR_REQUEST_BODY_VALIDATE_ERROR", (function () { return f })), n.d(t, "CLEAR_REQUEST_BODY_VALUE", (function () { return h })), n.d(t, "setSelectedServer", (function () { return d })), n.d(t, "setRequestBodyValue", (function () { return m })), n.d(t, "setRetainRequestBodyValueFlag", (function () { return v })), n.d(t, "setRequestBodyInclusion", (function () { return g })), n.d(t, "setActiveExamplesMember", (function () { return y })), n.d(t, "setRequestContentType", (function () { return b })), n.d(t, "setResponseContentType", (function () { return _ })), n.d(t, "setServerVariableValue", (function () { return w })), n.d(t, "setRequestBodyValidateError", (function () { return x })), n.d(t, "clearRequestBodyValidateError", (function () { return E })), n.d(t, "initRequestBodyValidateError", (function () { return S })), n.d(t, "clearRequestBodyValue", (function () { return C })); var r = "oas3_set_servers", o = "oas3_set_request_body_value", a = "oas3_set_request_body_retain_flag", i = "oas3_set_request_body_inclusion", s = "oas3_set_active_examples_member", u = "oas3_set_request_content_type", c = "oas3_set_response_content_type", l = "oas3_set_server_variable_value", p = "oas3_set_request_body_validate_error", f = "oas3_clear_request_body_validate_error", h = "oas3_clear_request_body_value"; function d(e, t) { return { type: r, payload: { selectedServerUrl: e, namespace: t } } } function m(e) { var t = e.value, n = e.pathMethod; return { type: o, payload: { value: t, pathMethod: n } } } var v = function (e) { var t = e.value, n = e.pathMethod; return { type: a, payload: { value: t, pathMethod: n } } }; function g(e) { var t = e.value, n = e.pathMethod, r = e.name; return { type: i, payload: { value: t, pathMethod: n, name: r } } } function y(e) { var t = e.name, n = e.pathMethod, r = e.contextType, o = e.contextName; return { type: s, payload: { name: t, pathMethod: n, contextType: r, contextName: o } } } function b(e) { var t = e.value, n = e.pathMethod; return { type: u, payload: { value: t, pathMethod: n } } } function _(e) { var t = e.value, n = e.path, r = e.method; return { type: c, payload: { value: t, path: n, method: r } } } function w(e) { var t = e.server, n = e.namespace, r = e.key, o = e.val; return { type: l, payload: { server: t, namespace: n, key: r, val: o } } } var x = function (e) { var t = e.path, n = e.method, r = e.validationErrors; return { type: p, payload: { path: t, method: n, validationErrors: r } } }, E = function (e) { var t = e.path, n = e.method; return { type: f, payload: { path: t, method: n } } }, S = function (e) { var t = e.pathMethod; return { type: f, payload: { path: t[0], method: t[1] } } }, C = function (e) { var t = e.pathMethod; return { type: h, payload: { pathMethod: t } } } }, function (e, t, n) { "use strict"; var r = !("undefined" == typeof window || !window.document || !window.document.createElement), o = { canUseDOM: r, canUseWorkers: "undefined" != typeof Worker, canUseEventListeners: r && !(!window.addEventListener && !window.attachEvent), canUseViewport: r && !!window.screen, isInWorker: !r }; e.exports = o }, function (e, t) { e.exports = function (e) { var t = typeof e; return null != e && ("object" == t || "function" == t) } }, function (e, t, n) { "use strict"; n.d(t, "b", (function () { return b })), n.d(t, "e", (function () { return _ })), n.d(t, "c", (function () { return x })), n.d(t, "a", (function () { return E })), n.d(t, "d", (function () { return S })); var r = n(51), o = n.n(r), a = n(18), i = n.n(a), s = n(37), u = n.n(s), c = n(2), l = n.n(c), p = n(19), f = n.n(p), h = n(59), d = n.n(h), m = n(353), v = n.n(m), g = function (e) { return String.prototype.toLowerCase.call(e) }, y = function (e) { return e.replace(/[^\w]/gi, "_") }; function b(e) { var t = e.openapi; return !!t && v()(t, "3") } function _(e, t) { var n = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : "", r = arguments.length > 3 && void 0 !== arguments[3] ? arguments[3] : {}, o = r.v2OperationIdCompatibilityMode; if (!e || "object" !== f()(e)) return null; var a = (e.operationId || "").replace(/\s/g, ""); return a.length ? y(e.operationId) : w(t, n, { v2OperationIdCompatibilityMode: o }) } function w(e, t) { var n, r = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : {}, o = r.v2OperationIdCompatibilityMode; if (o) { var a, i, s = l()(a = "".concat(t.toLowerCase(), "_")).call(a, e).replace(/[\s!@#$%^&*()_+=[{\]};:<>|./?,\\'""-]/g, "_"); return (s = s || l()(i = "".concat(e.substring(1), "_")).call(i, t)).replace(/((_){2,})/g, "_").replace(/^(_)*/g, "").replace(/([_])*$/g, "") } return l()(n = "".concat(g(t))).call(n, y(e)) } function x(e, t) { var n; return l()(n = "".concat(g(t), "-")).call(n, e) } function E(e, t) { return e && e.paths ? function (e, t) { return function (e, t, n) { if (!e || "object" !== f()(e) || !e.paths || "object" !== f()(e.paths)) return null; var r = e.paths; for (var o in r) for (var a in r[o]) if ("PARAMETERS" !== a.toUpperCase()) { var i = r[o][a]; if (i && "object" === f()(i)) { var s = { spec: e, pathName: o, method: a.toUpperCase(), operation: i }, u = t(s); if (n && u) return s } } return }(e, t, !0) || null }(e, (function (e) { var n, r = e.pathName, o = e.method, a = e.operation; if (!a || "object" !== f()(a)) return !1; var i = a.operationId, s = _(a, r, o), c = x(r, o); return u()(n = [s, c, i]).call(n, (function (e) { return e && e === t })) })) : null } function S(e) { var t = e.spec, n = t.paths, r = {}; if (!n || t.$$normalized) return e; for (var a in n) { var s = n[a]; if (d()(s)) { var c = s.parameters, p = function (e) { var n = s[e]; if (!d()(n)) return "continue"; var p = _(n, a, e); if (p) { r[p] ? r[p].push(n) : r[p] = [n]; var f = r[p]; if (f.length > 1) i()(f).call(f, (function (e, t) { var n; e.__originalOperationId = e.__originalOperationId || e.operationId, e.operationId = l()(n = "".concat(p)).call(n, t + 1) })); else if (void 0 !== n.operationId) { var h = f[0]; h.__originalOperationId = h.__originalOperationId || n.operationId, h.operationId = p } } if ("parameters" !== e) { var m = [], v = {}; for (var g in t) "produces" !== g && "consumes" !== g && "security" !== g || (v[g] = t[g], m.push(v)); if (c && (v.parameters = c, m.push(v)), m.length) { var y, b = o()(m); try { for (b.s(); !(y = b.n()).done;) { var w = y.value; for (var x in w) if (n[x]) { if ("parameters" === x) { var E, S = o()(w[x]); try { var C = function () { var e, t = E.value; u()(e = n[x]).call(e, (function (e) { return e.name && e.name === t.name || e.$ref && e.$ref === t.$ref || e.$$ref && e.$$ref === t.$$ref || e === t })) || n[x].push(t) }; for (S.s(); !(E = S.n()).done;)C() } catch (e) { S.e(e) } finally { S.f() } } } else n[x] = w[x] } } catch (e) { b.e(e) } finally { b.f() } } } }; for (var f in s) p(f) } } return t.$$normalized = !0, e } }, function (e, t, n) { "use strict"; n.r(t), n.d(t, "NEW_THROWN_ERR", (function () { return a })), n.d(t, "NEW_THROWN_ERR_BATCH", (function () { return i })), n.d(t, "NEW_SPEC_ERR", (function () { return s })), n.d(t, "NEW_SPEC_ERR_BATCH", (function () { return u })), n.d(t, "NEW_AUTH_ERR", (function () { return c })), n.d(t, "CLEAR", (function () { return l })), n.d(t, "CLEAR_BY", (function () { return p })), n.d(t, "newThrownErr", (function () { return f })), n.d(t, "newThrownErrBatch", (function () { return h })), n.d(t, "newSpecErr", (function () { return d })), n.d(t, "newSpecErrBatch", (function () { return m })), n.d(t, "newAuthErr", (function () { return v })), n.d(t, "clear", (function () { return g })), n.d(t, "clearBy", (function () { return y })); var r = n(143), o = n.n(r), a = "err_new_thrown_err", i = "err_new_thrown_err_batch", s = "err_new_spec_err", u = "err_new_spec_err_batch", c = "err_new_auth_err", l = "err_clear", p = "err_clear_by"; function f(e) { return { type: a, payload: o()(e) } } function h(e) { return { type: i, payload: e } } function d(e) { return { type: s, payload: e } } function m(e) { return { type: u, payload: e } } function v(e) { return { type: c, payload: e } } function g() { var e = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}; return { type: l, payload: e } } function y() { var e = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : function () { return !0 }; return { type: p, payload: e } } }, function (e, t, n) { var r = n(49), o = n(35), a = n(52), i = Object.defineProperty, s = {}, u = function (e) { throw e }; e.exports = function (e, t) { if (a(s, e)) return s[e]; t || (t = {}); var n = [][e], c = !!a(t, "ACCESSORS") && t.ACCESSORS, l = a(t, 0) ? t[0] : u, p = a(t, 1) ? t[1] : void 0; return s[e] = !!n && !o((function () { if (c && !r) return !0; var e = { length: -1 }; c ? i(e, 1, { enumerable: !0, get: u }) : e[1] = 1, n.call(e, l, p) })) } }, function (e, t) { "function" == typeof Object.create ? e.exports = function (e, t) { e.super_ = t, e.prototype = Object.create(t.prototype, { constructor: { value: e, enumerable: !1, writable: !0, configurable: !0 } }) } : e.exports = function (e, t) { e.super_ = t; var n = function () { }; n.prototype = t.prototype, e.prototype = new n, e.prototype.constructor = e } }, function (e, t, n) { var r = n(77), o = r.Buffer; function a(e, t) { for (var n in e) t[n] = e[n] } function i(e, t, n) { return o(e, t, n) } o.from && o.alloc && o.allocUnsafe && o.allocUnsafeSlow ? e.exports = r : (a(r, t), t.Buffer = i), a(o, i), i.from = function (e, t, n) { if ("number" == typeof e) throw new TypeError("Argument must not be a number"); return o(e, t, n) }, i.alloc = function (e, t, n) { if ("number" != typeof e) throw new TypeError("Argument must be a number"); var r = o(e); return void 0 !== t ? "string" == typeof n ? r.fill(t, n) : r.fill(t) : r.fill(0), r }, i.allocUnsafe = function (e) { if ("number" != typeof e) throw new TypeError("Argument must be a number"); return o(e) }, i.allocUnsafeSlow = function (e) { if ("number" != typeof e) throw new TypeError("Argument must be a number"); return r.SlowBuffer(e) } }, function (e, t, n) { var r; !function () { "use strict"; var n = {}.hasOwnProperty; function o() { for (var e = [], t = 0; t < arguments.length; t++) { var r = arguments[t]; if (r) { var a = typeof r; if ("string" === a || "number" === a) e.push(r); else if (Array.isArray(r) && r.length) { var i = o.apply(null, r); i && e.push(i) } else if ("object" === a) for (var s in r) n.call(r, s) && r[s] && e.push(s) } } return e.join(" ") } e.exports ? (o.default = o, e.exports = o) : void 0 === (r = function () { return o }.apply(t, [])) || (e.exports = r) }() }, function (e, t, n) { var r = n(114), o = n(59); e.exports = function (e) { if (!o(e)) return !1; var t = r(e); return "[object Function]" == t || "[object GeneratorFunction]" == t || "[object AsyncFunction]" == t || "[object Proxy]" == t } }, function (e, t, n) { e.exports = n(647) }, function (e, t, n) { e.exports = n(902) }, function (e, t, n) { var r = n(177), o = n(128); e.exports = function (e) { return r(o(e)) } }, function (e, t, n) { var r = n(49), o = n(71), a = n(108); e.exports = r ? function (e, t, n) { return o.f(e, t, a(1, n)) } : function (e, t, n) { return e[t] = n, e } }, function (e, t, n) { var r = n(49), o = n(357), a = n(53), i = n(178), s = Object.defineProperty; t.f = r ? s : function (e, t, n) { if (a(e), t = i(t, !0), a(n), o) try { return s(e, t, n) } catch (e) { } if ("get" in n || "set" in n) throw TypeError("Accessors not supported"); return "value" in n && (e[t] = n.value), e } }, function (e, t, n) { var r = n(33), o = n(42), a = function (e) { return "function" == typeof e ? e : void 0 }; e.exports = function (e, t) { return arguments.length < 2 ? a(r[e]) || a(o[e]) : r[e] && r[e][t] || o[e] && o[e][t] } }, function (e, t, n) { var r = n(128); e.exports = function (e) { return Object(r(e)) } }, function (e, t, n) { n(154); var r = n(561), o = n(42), a = n(90), i = n(70), s = n(111), u = n(39)("toStringTag"); for (var c in r) { var l = o[c], p = l && l.prototype; p && a(p) !== u && i(p, u, c), s[c] = s.Array } }, function (e, t, n) { var r = n(407), o = "object" == typeof self && self && self.Object === Object && self, a = r || o || Function("return this")(); e.exports = a }, function (e, t, n) { "use strict"; e.exports = { debugTool: null } }, function (e, t, n) { "use strict"; (function (e) { var r = n(592), o = n(593), a = n(373); function i() { return u.TYPED_ARRAY_SUPPORT ? 2147483647 : 1073741823 } function s(e, t) { if (i() < t) throw new RangeError("Invalid typed array length"); return u.TYPED_ARRAY_SUPPORT ? (e = new Uint8Array(t)).__proto__ = u.prototype : (null === e && (e = new u(t)), e.length = t), e } function u(e, t, n) { if (!(u.TYPED_ARRAY_SUPPORT || this instanceof u)) return new u(e, t, n); if ("number" == typeof e) { if ("string" == typeof t) throw new Error("If encoding is specified then the first argument must be a string"); return p(this, e) } return c(this, e, t, n) } function c(e, t, n, r) { if ("number" == typeof t) throw new TypeError('"value" argument must not be a number'); return "undefined" != typeof ArrayBuffer && t instanceof ArrayBuffer ? function (e, t, n, r) { if (t.byteLength, n < 0 || t.byteLength < n) throw new RangeError("'offset' is out of bounds"); if (t.byteLength < n + (r || 0)) throw new RangeError("'length' is out of bounds"); t = void 0 === n && void 0 === r ? new Uint8Array(t) : void 0 === r ? new Uint8Array(t, n) : new Uint8Array(t, n, r); u.TYPED_ARRAY_SUPPORT ? (e = t).__proto__ = u.prototype : e = f(e, t); return e }(e, t, n, r) : "string" == typeof t ? function (e, t, n) { "string" == typeof n && "" !== n || (n = "utf8"); if (!u.isEncoding(n)) throw new TypeError('"encoding" must be a valid string encoding'); var r = 0 | d(t, n), o = (e = s(e, r)).write(t, n); o !== r && (e = e.slice(0, o)); return e }(e, t, n) : function (e, t) { if (u.isBuffer(t)) { var n = 0 | h(t.length); return 0 === (e = s(e, n)).length || t.copy(e, 0, 0, n), e } if (t) { if ("undefined" != typeof ArrayBuffer && t.buffer instanceof ArrayBuffer || "length" in t) return "number" != typeof t.length || (r = t.length) != r ? s(e, 0) : f(e, t); if ("Buffer" === t.type && a(t.data)) return f(e, t.data) } var r; throw new TypeError("First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object.") }(e, t) } function l(e) { if ("number" != typeof e) throw new TypeError('"size" argument must be a number'); if (e < 0) throw new RangeError('"size" argument must not be negative') } function p(e, t) { if (l(t), e = s(e, t < 0 ? 0 : 0 | h(t)), !u.TYPED_ARRAY_SUPPORT) for (var n = 0; n < t; ++n)e[n] = 0; return e } function f(e, t) { var n = t.length < 0 ? 0 : 0 | h(t.length); e = s(e, n); for (var r = 0; r < n; r += 1)e[r] = 255 & t[r]; return e } function h(e) { if (e >= i()) throw new RangeError("Attempt to allocate Buffer larger than maximum size: 0x" + i().toString(16) + " bytes"); return 0 | e } function d(e, t) { if (u.isBuffer(e)) return e.length; if ("undefined" != typeof ArrayBuffer && "function" == typeof ArrayBuffer.isView && (ArrayBuffer.isView(e) || e instanceof ArrayBuffer)) return e.byteLength; "string" != typeof e && (e = "" + e); var n = e.length; if (0 === n) return 0; for (var r = !1; ;)switch (t) { case "ascii": case "latin1": case "binary": return n; case "utf8": case "utf-8": case void 0: return q(e).length; case "ucs2": case "ucs-2": case "utf16le": case "utf-16le": return 2 * n; case "hex": return n >>> 1; case "base64": return z(e).length; default: if (r) return q(e).length; t = ("" + t).toLowerCase(), r = !0 } } function m(e, t, n) { var r = !1; if ((void 0 === t || t < 0) && (t = 0), t > this.length) return ""; if ((void 0 === n || n > this.length) && (n = this.length), n <= 0) return ""; if ((n >>>= 0) <= (t >>>= 0)) return ""; for (e || (e = "utf8"); ;)switch (e) { case "hex": return T(this, t, n); case "utf8": case "utf-8": return A(this, t, n); case "ascii": return O(this, t, n); case "latin1": case "binary": return j(this, t, n); case "base64": return C(this, t, n); case "ucs2": case "ucs-2": case "utf16le": case "utf-16le": return I(this, t, n); default: if (r) throw new TypeError("Unknown encoding: " + e); e = (e + "").toLowerCase(), r = !0 } } function v(e, t, n) { var r = e[t]; e[t] = e[n], e[n] = r } function g(e, t, n, r, o) { if (0 === e.length) return -1; if ("string" == typeof n ? (r = n, n = 0) : n > 2147483647 ? n = 2147483647 : n < -2147483648 && (n = -2147483648), n = +n, isNaN(n) && (n = o ? 0 : e.length - 1), n < 0 && (n = e.length + n), n >= e.length) { if (o) return -1; n = e.length - 1 } else if (n < 0) { if (!o) return -1; n = 0 } if ("string" == typeof t && (t = u.from(t, r)), u.isBuffer(t)) return 0 === t.length ? -1 : y(e, t, n, r, o); if ("number" == typeof t) return t &= 255, u.TYPED_ARRAY_SUPPORT && "function" == typeof Uint8Array.prototype.indexOf ? o ? Uint8Array.prototype.indexOf.call(e, t, n) : Uint8Array.prototype.lastIndexOf.call(e, t, n) : y(e, [t], n, r, o); throw new TypeError("val must be string, number or Buffer") } function y(e, t, n, r, o) { var a, i = 1, s = e.length, u = t.length; if (void 0 !== r && ("ucs2" === (r = String(r).toLowerCase()) || "ucs-2" === r || "utf16le" === r || "utf-16le" === r)) { if (e.length < 2 || t.length < 2) return -1; i = 2, s /= 2, u /= 2, n /= 2 } function c(e, t) { return 1 === i ? e[t] : e.readUInt16BE(t * i) } if (o) { var l = -1; for (a = n; a < s; a++)if (c(e, a) === c(t, -1 === l ? 0 : a - l)) { if (-1 === l && (l = a), a - l + 1 === u) return l * i } else -1 !== l && (a -= a - l), l = -1 } else for (n + u > s && (n = s - u), a = n; a >= 0; a--) { for (var p = !0, f = 0; f < u; f++)if (c(e, a + f) !== c(t, f)) { p = !1; break } if (p) return a } return -1 } function b(e, t, n, r) { n = Number(n) || 0; var o = e.length - n; r ? (r = Number(r)) > o && (r = o) : r = o; var a = t.length; if (a % 2 != 0) throw new TypeError("Invalid hex string"); r > a / 2 && (r = a / 2); for (var i = 0; i < r; ++i) { var s = parseInt(t.substr(2 * i, 2), 16); if (isNaN(s)) return i; e[n + i] = s } return i } function _(e, t, n, r) { return V(q(t, e.length - n), e, n, r) } function w(e, t, n, r) { return V(function (e) { for (var t = [], n = 0; n < e.length; ++n)t.push(255 & e.charCodeAt(n)); return t }(t), e, n, r) } function x(e, t, n, r) { return w(e, t, n, r) } function E(e, t, n, r) { return V(z(t), e, n, r) } function S(e, t, n, r) { return V(function (e, t) { for (var n, r, o, a = [], i = 0; i < e.length && !((t -= 2) < 0); ++i)r = (n = e.charCodeAt(i)) >> 8, o = n % 256, a.push(o), a.push(r); return a }(t, e.length - n), e, n, r) } function C(e, t, n) { return 0 === t && n === e.length ? r.fromByteArray(e) : r.fromByteArray(e.slice(t, n)) } function A(e, t, n) { n = Math.min(e.length, n); for (var r = [], o = t; o < n;) { var a, i, s, u, c = e[o], l = null, p = c > 239 ? 4 : c > 223 ? 3 : c > 191 ? 2 : 1; if (o + p <= n) switch (p) { case 1: c < 128 && (l = c); break; case 2: 128 == (192 & (a = e[o + 1])) && (u = (31 & c) << 6 | 63 & a) > 127 && (l = u); break; case 3: a = e[o + 1], i = e[o + 2], 128 == (192 & a) && 128 == (192 & i) && (u = (15 & c) << 12 | (63 & a) << 6 | 63 & i) > 2047 && (u < 55296 || u > 57343) && (l = u); break; case 4: a = e[o + 1], i = e[o + 2], s = e[o + 3], 128 == (192 & a) && 128 == (192 & i) && 128 == (192 & s) && (u = (15 & c) << 18 | (63 & a) << 12 | (63 & i) << 6 | 63 & s) > 65535 && u < 1114112 && (l = u) }null === l ? (l = 65533, p = 1) : l > 65535 && (l -= 65536, r.push(l >>> 10 & 1023 | 55296), l = 56320 | 1023 & l), r.push(l), o += p } return function (e) { var t = e.length; if (t <= k) return String.fromCharCode.apply(String, e); var n = "", r = 0; for (; r < t;)n += String.fromCharCode.apply(String, e.slice(r, r += k)); return n }(r) } t.Buffer = u, t.SlowBuffer = function (e) { +e != e && (e = 0); return u.alloc(+e) }, t.INSPECT_MAX_BYTES = 50, u.TYPED_ARRAY_SUPPORT = void 0 !== e.TYPED_ARRAY_SUPPORT ? e.TYPED_ARRAY_SUPPORT : function () { try { var e = new Uint8Array(1); return e.__proto__ = { __proto__: Uint8Array.prototype, foo: function () { return 42 } }, 42 === e.foo() && "function" == typeof e.subarray && 0 === e.subarray(1, 1).byteLength } catch (e) { return !1 } }(), t.kMaxLength = i(), u.poolSize = 8192, u._augment = function (e) { return e.__proto__ = u.prototype, e }, u.from = function (e, t, n) { return c(null, e, t, n) }, u.TYPED_ARRAY_SUPPORT && (u.prototype.__proto__ = Uint8Array.prototype, u.__proto__ = Uint8Array, "undefined" != typeof Symbol && Symbol.species && u[Symbol.species] === u && Object.defineProperty(u, Symbol.species, { value: null, configurable: !0 })), u.alloc = function (e, t, n) { return function (e, t, n, r) { return l(t), t <= 0 ? s(e, t) : void 0 !== n ? "string" == typeof r ? s(e, t).fill(n, r) : s(e, t).fill(n) : s(e, t) }(null, e, t, n) }, u.allocUnsafe = function (e) { return p(null, e) }, u.allocUnsafeSlow = function (e) { return p(null, e) }, u.isBuffer = function (e) { return !(null == e || !e._isBuffer) }, u.compare = function (e, t) { if (!u.isBuffer(e) || !u.isBuffer(t)) throw new TypeError("Arguments must be Buffers"); if (e === t) return 0; for (var n = e.length, r = t.length, o = 0, a = Math.min(n, r); o < a; ++o)if (e[o] !== t[o]) { n = e[o], r = t[o]; break } return n < r ? -1 : r < n ? 1 : 0 }, u.isEncoding = function (e) { switch (String(e).toLowerCase()) { case "hex": case "utf8": case "utf-8": case "ascii": case "latin1": case "binary": case "base64": case "ucs2": case "ucs-2": case "utf16le": case "utf-16le": return !0; default: return !1 } }, u.concat = function (e, t) { if (!a(e)) throw new TypeError('"list" argument must be an Array of Buffers'); if (0 === e.length) return u.alloc(0); var n; if (void 0 === t) for (t = 0, n = 0; n < e.length; ++n)t += e[n].length; var r = u.allocUnsafe(t), o = 0; for (n = 0; n < e.length; ++n) { var i = e[n]; if (!u.isBuffer(i)) throw new TypeError('"list" argument must be an Array of Buffers'); i.copy(r, o), o += i.length } return r }, u.byteLength = d, u.prototype._isBuffer = !0, u.prototype.swap16 = function () { var e = this.length; if (e % 2 != 0) throw new RangeError("Buffer size must be a multiple of 16-bits"); for (var t = 0; t < e; t += 2)v(this, t, t + 1); return this }, u.prototype.swap32 = function () { var e = this.length; if (e % 4 != 0) throw new RangeError("Buffer size must be a multiple of 32-bits"); for (var t = 0; t < e; t += 4)v(this, t, t + 3), v(this, t + 1, t + 2); return this }, u.prototype.swap64 = function () { var e = this.length; if (e % 8 != 0) throw new RangeError("Buffer size must be a multiple of 64-bits"); for (var t = 0; t < e; t += 8)v(this, t, t + 7), v(this, t + 1, t + 6), v(this, t + 2, t + 5), v(this, t + 3, t + 4); return this }, u.prototype.toString = function () { var e = 0 | this.length; return 0 === e ? "" : 0 === arguments.length ? A(this, 0, e) : m.apply(this, arguments) }, u.prototype.equals = function (e) { if (!u.isBuffer(e)) throw new TypeError("Argument must be a Buffer"); return this === e || 0 === u.compare(this, e) }, u.prototype.inspect = function () { var e = "", n = t.INSPECT_MAX_BYTES; return this.length > 0 && (e = this.toString("hex", 0, n).match(/.{2}/g).join(" "), this.length > n && (e += " ... ")), "" }, u.prototype.compare = function (e, t, n, r, o) { if (!u.isBuffer(e)) throw new TypeError("Argument must be a Buffer"); if (void 0 === t && (t = 0), void 0 === n && (n = e ? e.length : 0), void 0 === r && (r = 0), void 0 === o && (o = this.length), t < 0 || n > e.length || r < 0 || o > this.length) throw new RangeError("out of range index"); if (r >= o && t >= n) return 0; if (r >= o) return -1; if (t >= n) return 1; if (this === e) return 0; for (var a = (o >>>= 0) - (r >>>= 0), i = (n >>>= 0) - (t >>>= 0), s = Math.min(a, i), c = this.slice(r, o), l = e.slice(t, n), p = 0; p < s; ++p)if (c[p] !== l[p]) { a = c[p], i = l[p]; break } return a < i ? -1 : i < a ? 1 : 0 }, u.prototype.includes = function (e, t, n) { return -1 !== this.indexOf(e, t, n) }, u.prototype.indexOf = function (e, t, n) { return g(this, e, t, n, !0) }, u.prototype.lastIndexOf = function (e, t, n) { return g(this, e, t, n, !1) }, u.prototype.write = function (e, t, n, r) { if (void 0 === t) r = "utf8", n = this.length, t = 0; else if (void 0 === n && "string" == typeof t) r = t, n = this.length, t = 0; else { if (!isFinite(t)) throw new Error("Buffer.write(string, encoding, offset[, length]) is no longer supported"); t |= 0, isFinite(n) ? (n |= 0, void 0 === r && (r = "utf8")) : (r = n, n = void 0) } var o = this.length - t; if ((void 0 === n || n > o) && (n = o), e.length > 0 && (n < 0 || t < 0) || t > this.length) throw new RangeError("Attempt to write outside buffer bounds"); r || (r = "utf8"); for (var a = !1; ;)switch (r) { case "hex": return b(this, e, t, n); case "utf8": case "utf-8": return _(this, e, t, n); case "ascii": return w(this, e, t, n); case "latin1": case "binary": return x(this, e, t, n); case "base64": return E(this, e, t, n); case "ucs2": case "ucs-2": case "utf16le": case "utf-16le": return S(this, e, t, n); default: if (a) throw new TypeError("Unknown encoding: " + r); r = ("" + r).toLowerCase(), a = !0 } }, u.prototype.toJSON = function () { return { type: "Buffer", data: Array.prototype.slice.call(this._arr || this, 0) } }; var k = 4096; function O(e, t, n) { var r = ""; n = Math.min(e.length, n); for (var o = t; o < n; ++o)r += String.fromCharCode(127 & e[o]); return r } function j(e, t, n) { var r = ""; n = Math.min(e.length, n); for (var o = t; o < n; ++o)r += String.fromCharCode(e[o]); return r } function T(e, t, n) { var r = e.length; (!t || t < 0) && (t = 0), (!n || n < 0 || n > r) && (n = r); for (var o = "", a = t; a < n; ++a)o += U(e[a]); return o } function I(e, t, n) { for (var r = e.slice(t, n), o = "", a = 0; a < r.length; a += 2)o += String.fromCharCode(r[a] + 256 * r[a + 1]); return o } function P(e, t, n) { if (e % 1 != 0 || e < 0) throw new RangeError("offset is not uint"); if (e + t > n) throw new RangeError("Trying to access beyond buffer length") } function N(e, t, n, r, o, a) { if (!u.isBuffer(e)) throw new TypeError('"buffer" argument must be a Buffer instance'); if (t > o || t < a) throw new RangeError('"value" argument is out of bounds'); if (n + r > e.length) throw new RangeError("Index out of range") } function M(e, t, n, r) { t < 0 && (t = 65535 + t + 1); for (var o = 0, a = Math.min(e.length - n, 2); o < a; ++o)e[n + o] = (t & 255 << 8 * (r ? o : 1 - o)) >>> 8 * (r ? o : 1 - o) } function R(e, t, n, r) { t < 0 && (t = 4294967295 + t + 1); for (var o = 0, a = Math.min(e.length - n, 4); o < a; ++o)e[n + o] = t >>> 8 * (r ? o : 3 - o) & 255 } function D(e, t, n, r, o, a) { if (n + r > e.length) throw new RangeError("Index out of range"); if (n < 0) throw new RangeError("Index out of range") } function L(e, t, n, r, a) { return a || D(e, 0, n, 4), o.write(e, t, n, r, 23, 4), n + 4 } function B(e, t, n, r, a) { return a || D(e, 0, n, 8), o.write(e, t, n, r, 52, 8), n + 8 } u.prototype.slice = function (e, t) { var n, r = this.length; if ((e = ~~e) < 0 ? (e += r) < 0 && (e = 0) : e > r && (e = r), (t = void 0 === t ? r : ~~t) < 0 ? (t += r) < 0 && (t = 0) : t > r && (t = r), t < e && (t = e), u.TYPED_ARRAY_SUPPORT) (n = this.subarray(e, t)).__proto__ = u.prototype; else { var o = t - e; n = new u(o, void 0); for (var a = 0; a < o; ++a)n[a] = this[a + e] } return n }, u.prototype.readUIntLE = function (e, t, n) { e |= 0, t |= 0, n || P(e, t, this.length); for (var r = this[e], o = 1, a = 0; ++a < t && (o *= 256);)r += this[e + a] * o; return r }, u.prototype.readUIntBE = function (e, t, n) { e |= 0, t |= 0, n || P(e, t, this.length); for (var r = this[e + --t], o = 1; t > 0 && (o *= 256);)r += this[e + --t] * o; return r }, u.prototype.readUInt8 = function (e, t) { return t || P(e, 1, this.length), this[e] }, u.prototype.readUInt16LE = function (e, t) { return t || P(e, 2, this.length), this[e] | this[e + 1] << 8 }, u.prototype.readUInt16BE = function (e, t) { return t || P(e, 2, this.length), this[e] << 8 | this[e + 1] }, u.prototype.readUInt32LE = function (e, t) { return t || P(e, 4, this.length), (this[e] | this[e + 1] << 8 | this[e + 2] << 16) + 16777216 * this[e + 3] }, u.prototype.readUInt32BE = function (e, t) { return t || P(e, 4, this.length), 16777216 * this[e] + (this[e + 1] << 16 | this[e + 2] << 8 | this[e + 3]) }, u.prototype.readIntLE = function (e, t, n) { e |= 0, t |= 0, n || P(e, t, this.length); for (var r = this[e], o = 1, a = 0; ++a < t && (o *= 256);)r += this[e + a] * o; return r >= (o *= 128) && (r -= Math.pow(2, 8 * t)), r }, u.prototype.readIntBE = function (e, t, n) { e |= 0, t |= 0, n || P(e, t, this.length); for (var r = t, o = 1, a = this[e + --r]; r > 0 && (o *= 256);)a += this[e + --r] * o; return a >= (o *= 128) && (a -= Math.pow(2, 8 * t)), a }, u.prototype.readInt8 = function (e, t) { return t || P(e, 1, this.length), 128 & this[e] ? -1 * (255 - this[e] + 1) : this[e] }, u.prototype.readInt16LE = function (e, t) { t || P(e, 2, this.length); var n = this[e] | this[e + 1] << 8; return 32768 & n ? 4294901760 | n : n }, u.prototype.readInt16BE = function (e, t) { t || P(e, 2, this.length); var n = this[e + 1] | this[e] << 8; return 32768 & n ? 4294901760 | n : n }, u.prototype.readInt32LE = function (e, t) { return t || P(e, 4, this.length), this[e] | this[e + 1] << 8 | this[e + 2] << 16 | this[e + 3] << 24 }, u.prototype.readInt32BE = function (e, t) { return t || P(e, 4, this.length), this[e] << 24 | this[e + 1] << 16 | this[e + 2] << 8 | this[e + 3] }, u.prototype.readFloatLE = function (e, t) { return t || P(e, 4, this.length), o.read(this, e, !0, 23, 4) }, u.prototype.readFloatBE = function (e, t) { return t || P(e, 4, this.length), o.read(this, e, !1, 23, 4) }, u.prototype.readDoubleLE = function (e, t) { return t || P(e, 8, this.length), o.read(this, e, !0, 52, 8) }, u.prototype.readDoubleBE = function (e, t) { return t || P(e, 8, this.length), o.read(this, e, !1, 52, 8) }, u.prototype.writeUIntLE = function (e, t, n, r) { (e = +e, t |= 0, n |= 0, r) || N(this, e, t, n, Math.pow(2, 8 * n) - 1, 0); var o = 1, a = 0; for (this[t] = 255 & e; ++a < n && (o *= 256);)this[t + a] = e / o & 255; return t + n }, u.prototype.writeUIntBE = function (e, t, n, r) { (e = +e, t |= 0, n |= 0, r) || N(this, e, t, n, Math.pow(2, 8 * n) - 1, 0); var o = n - 1, a = 1; for (this[t + o] = 255 & e; --o >= 0 && (a *= 256);)this[t + o] = e / a & 255; return t + n }, u.prototype.writeUInt8 = function (e, t, n) { return e = +e, t |= 0, n || N(this, e, t, 1, 255, 0), u.TYPED_ARRAY_SUPPORT || (e = Math.floor(e)), this[t] = 255 & e, t + 1 }, u.prototype.writeUInt16LE = function (e, t, n) { return e = +e, t |= 0, n || N(this, e, t, 2, 65535, 0), u.TYPED_ARRAY_SUPPORT ? (this[t] = 255 & e, this[t + 1] = e >>> 8) : M(this, e, t, !0), t + 2 }, u.prototype.writeUInt16BE = function (e, t, n) { return e = +e, t |= 0, n || N(this, e, t, 2, 65535, 0), u.TYPED_ARRAY_SUPPORT ? (this[t] = e >>> 8, this[t + 1] = 255 & e) : M(this, e, t, !1), t + 2 }, u.prototype.writeUInt32LE = function (e, t, n) { return e = +e, t |= 0, n || N(this, e, t, 4, 4294967295, 0), u.TYPED_ARRAY_SUPPORT ? (this[t + 3] = e >>> 24, this[t + 2] = e >>> 16, this[t + 1] = e >>> 8, this[t] = 255 & e) : R(this, e, t, !0), t + 4 }, u.prototype.writeUInt32BE = function (e, t, n) { return e = +e, t |= 0, n || N(this, e, t, 4, 4294967295, 0), u.TYPED_ARRAY_SUPPORT ? (this[t] = e >>> 24, this[t + 1] = e >>> 16, this[t + 2] = e >>> 8, this[t + 3] = 255 & e) : R(this, e, t, !1), t + 4 }, u.prototype.writeIntLE = function (e, t, n, r) { if (e = +e, t |= 0, !r) { var o = Math.pow(2, 8 * n - 1); N(this, e, t, n, o - 1, -o) } var a = 0, i = 1, s = 0; for (this[t] = 255 & e; ++a < n && (i *= 256);)e < 0 && 0 === s && 0 !== this[t + a - 1] && (s = 1), this[t + a] = (e / i >> 0) - s & 255; return t + n }, u.prototype.writeIntBE = function (e, t, n, r) { if (e = +e, t |= 0, !r) { var o = Math.pow(2, 8 * n - 1); N(this, e, t, n, o - 1, -o) } var a = n - 1, i = 1, s = 0; for (this[t + a] = 255 & e; --a >= 0 && (i *= 256);)e < 0 && 0 === s && 0 !== this[t + a + 1] && (s = 1), this[t + a] = (e / i >> 0) - s & 255; return t + n }, u.prototype.writeInt8 = function (e, t, n) { return e = +e, t |= 0, n || N(this, e, t, 1, 127, -128), u.TYPED_ARRAY_SUPPORT || (e = Math.floor(e)), e < 0 && (e = 255 + e + 1), this[t] = 255 & e, t + 1 }, u.prototype.writeInt16LE = function (e, t, n) { return e = +e, t |= 0, n || N(this, e, t, 2, 32767, -32768), u.TYPED_ARRAY_SUPPORT ? (this[t] = 255 & e, this[t + 1] = e >>> 8) : M(this, e, t, !0), t + 2 }, u.prototype.writeInt16BE = function (e, t, n) { return e = +e, t |= 0, n || N(this, e, t, 2, 32767, -32768), u.TYPED_ARRAY_SUPPORT ? (this[t] = e >>> 8, this[t + 1] = 255 & e) : M(this, e, t, !1), t + 2 }, u.prototype.writeInt32LE = function (e, t, n) { return e = +e, t |= 0, n || N(this, e, t, 4, 2147483647, -2147483648), u.TYPED_ARRAY_SUPPORT ? (this[t] = 255 & e, this[t + 1] = e >>> 8, this[t + 2] = e >>> 16, this[t + 3] = e >>> 24) : R(this, e, t, !0), t + 4 }, u.prototype.writeInt32BE = function (e, t, n) { return e = +e, t |= 0, n || N(this, e, t, 4, 2147483647, -2147483648), e < 0 && (e = 4294967295 + e + 1), u.TYPED_ARRAY_SUPPORT ? (this[t] = e >>> 24, this[t + 1] = e >>> 16, this[t + 2] = e >>> 8, this[t + 3] = 255 & e) : R(this, e, t, !1), t + 4 }, u.prototype.writeFloatLE = function (e, t, n) { return L(this, e, t, !0, n) }, u.prototype.writeFloatBE = function (e, t, n) { return L(this, e, t, !1, n) }, u.prototype.writeDoubleLE = function (e, t, n) { return B(this, e, t, !0, n) }, u.prototype.writeDoubleBE = function (e, t, n) { return B(this, e, t, !1, n) }, u.prototype.copy = function (e, t, n, r) { if (n || (n = 0), r || 0 === r || (r = this.length), t >= e.length && (t = e.length), t || (t = 0), r > 0 && r < n && (r = n), r === n) return 0; if (0 === e.length || 0 === this.length) return 0; if (t < 0) throw new RangeError("targetStart out of bounds"); if (n < 0 || n >= this.length) throw new RangeError("sourceStart out of bounds"); if (r < 0) throw new RangeError("sourceEnd out of bounds"); r > this.length && (r = this.length), e.length - t < r - n && (r = e.length - t + n); var o, a = r - n; if (this === e && n < t && t < r) for (o = a - 1; o >= 0; --o)e[o + t] = this[o + n]; else if (a < 1e3 || !u.TYPED_ARRAY_SUPPORT) for (o = 0; o < a; ++o)e[o + t] = this[o + n]; else Uint8Array.prototype.set.call(e, this.subarray(n, n + a), t); return a }, u.prototype.fill = function (e, t, n, r) { if ("string" == typeof e) { if ("string" == typeof t ? (r = t, t = 0, n = this.length) : "string" == typeof n && (r = n, n = this.length), 1 === e.length) { var o = e.charCodeAt(0); o < 256 && (e = o) } if (void 0 !== r && "string" != typeof r) throw new TypeError("encoding must be a string"); if ("string" == typeof r && !u.isEncoding(r)) throw new TypeError("Unknown encoding: " + r) } else "number" == typeof e && (e &= 255); if (t < 0 || this.length < t || this.length < n) throw new RangeError("Out of range index"); if (n <= t) return this; var a; if (t >>>= 0, n = void 0 === n ? this.length : n >>> 0, e || (e = 0), "number" == typeof e) for (a = t; a < n; ++a)this[a] = e; else { var i = u.isBuffer(e) ? e : q(new u(e, r).toString()), s = i.length; for (a = 0; a < n - t; ++a)this[a + t] = i[a % s] } return this }; var F = /[^+\/0-9A-Za-z-_]/g; function U(e) { return e < 16 ? "0" + e.toString(16) : e.toString(16) } function q(e, t) { var n; t = t || 1 / 0; for (var r = e.length, o = null, a = [], i = 0; i < r; ++i) { if ((n = e.charCodeAt(i)) > 55295 && n < 57344) { if (!o) { if (n > 56319) { (t -= 3) > -1 && a.push(239, 191, 189); continue } if (i + 1 === r) { (t -= 3) > -1 && a.push(239, 191, 189); continue } o = n; continue } if (n < 56320) { (t -= 3) > -1 && a.push(239, 191, 189), o = n; continue } n = 65536 + (o - 55296 << 10 | n - 56320) } else o && (t -= 3) > -1 && a.push(239, 191, 189); if (o = null, n < 128) { if ((t -= 1) < 0) break; a.push(n) } else if (n < 2048) { if ((t -= 2) < 0) break; a.push(n >> 6 | 192, 63 & n | 128) } else if (n < 65536) { if ((t -= 3) < 0) break; a.push(n >> 12 | 224, n >> 6 & 63 | 128, 63 & n | 128) } else { if (!(n < 1114112)) throw new Error("Invalid code point"); if ((t -= 4) < 0) break; a.push(n >> 18 | 240, n >> 12 & 63 | 128, n >> 6 & 63 | 128, 63 & n | 128) } } return a } function z(e) { return r.toByteArray(function (e) { if ((e = function (e) { return e.trim ? e.trim() : e.replace(/^\s+|\s+$/g, "") }(e).replace(F, "")).length < 2) return ""; for (; e.length % 4 != 0;)e += "="; return e }(e)) } function V(e, t, n, r) { for (var o = 0; o < r && !(o + n >= t.length || o >= e.length); ++o)t[o + n] = e[o]; return o } }).call(this, n(55)) }, function (e, t, n) { "use strict"; var r = n(848); e.exports = r }, function (e, t, n) { var r = n(908); function o(e, t, n, o, a, i, s) { try { var u = e[i](s), c = u.value } catch (e) { return void n(e) } u.done ? t(c) : r.resolve(c).then(o, a) } e.exports = function (e) { return function () { var t = this, n = arguments; return new r((function (r, a) { var i = e.apply(t, n); function s(e) { o(i, r, a, s, u, "next", e) } function u(e) { o(i, r, a, s, u, "throw", e) } s(void 0) })) } } }, function (e, t) { e.exports = function (e) { if ("function" != typeof e) throw TypeError(String(e) + " is not a function"); return e } }, function (e, t, n) { var r = n(151), o = Math.min; e.exports = function (e) { return e > 0 ? o(r(e), 9007199254740991) : 0 } }, function (e, t, n) { var r, o, a, i = n(364), s = n(42), u = n(45), c = n(70), l = n(52), p = n(234), f = n(180), h = n(152), d = s.WeakMap; if (i) { var m = p.state || (p.state = new d), v = m.get, g = m.has, y = m.set; r = function (e, t) { return t.facade = e, y.call(m, e, t), t }, o = function (e) { return v.call(m, e) || {} }, a = function (e) { return g.call(m, e) } } else { var b = f("state"); h[b] = !0, r = function (e, t) { return t.facade = e, c(e, b, t), t }, o = function (e) { return l(e, b) ? e[b] : {} }, a = function (e) { return l(e, b) } } e.exports = { set: r, get: o, has: a, enforce: function (e) { return a(e) ? o(e) : r(e, {}) }, getterFor: function (e) { return function (t) { var n; if (!u(t) || (n = o(t)).type !== e) throw TypeError("Incompatible receiver, " + e + " required"); return n } } } }, function (e, t, n) { "use strict"; function r(e) { return function () { return e } } var o = function () { }; o.thatReturns = r, o.thatReturnsFalse = r(!1), o.thatReturnsTrue = r(!0), o.thatReturnsNull = r(null), o.thatReturnsThis = function () { return this }, o.thatReturnsArgument = function (e) { return e }, e.exports = o }, function (e, t, n) { "use strict"; var r = n(31), o = n(40), a = n(475), i = n(124), s = n(476), u = n(140), c = n(204), l = n(26), p = [], f = 0, h = a.getPooled(), d = !1, m = null; function v() { x.ReactReconcileTransaction && m || r("123") } var g = [{ initialize: function () { this.dirtyComponentsLength = p.length }, close: function () { this.dirtyComponentsLength !== p.length ? (p.splice(0, this.dirtyComponentsLength), w()) : p.length = 0 } }, { initialize: function () { this.callbackQueue.reset() }, close: function () { this.callbackQueue.notifyAll() } }]; function y() { this.reinitializeTransaction(), this.dirtyComponentsLength = null, this.callbackQueue = a.getPooled(), this.reconcileTransaction = x.ReactReconcileTransaction.getPooled(!0) } function b(e, t) { return e._mountOrder - t._mountOrder } function _(e) { var t = e.dirtyComponentsLength; t !== p.length && r("124", t, p.length), p.sort(b), f++; for (var n = 0; n < t; n++) { var o, a = p[n], i = a._pendingCallbacks; if (a._pendingCallbacks = null, s.logTopLevelRenders) { var c = a; a._currentElement.type.isReactTopLevelWrapper && (c = a._renderedComponent), o = "React update: " + c.getName(), console.time(o) } if (u.performUpdateIfNecessary(a, e.reconcileTransaction, f), o && console.timeEnd(o), i) for (var l = 0; l < i.length; l++)e.callbackQueue.enqueue(i[l], a.getPublicInstance()) } } o(y.prototype, c, { getTransactionWrappers: function () { return g }, destructor: function () { this.dirtyComponentsLength = null, a.release(this.callbackQueue), this.callbackQueue = null, x.ReactReconcileTransaction.release(this.reconcileTransaction), this.reconcileTransaction = null }, perform: function (e, t, n) { return c.perform.call(this, this.reconcileTransaction.perform, this.reconcileTransaction, e, t, n) } }), i.addPoolingTo(y); var w = function () { for (; p.length || d;) { if (p.length) { var e = y.getPooled(); e.perform(_, null, e), y.release(e) } if (d) { d = !1; var t = h; h = a.getPooled(), t.notifyAll(), a.release(t) } } }; var x = { ReactReconcileTransaction: null, batchedUpdates: function (e, t, n, r, o, a) { return v(), m.batchedUpdates(e, t, n, r, o, a) }, enqueueUpdate: function e(t) { v(), m.isBatchingUpdates ? (p.push(t), null == t._updateBatchNumber && (t._updateBatchNumber = f + 1)) : m.batchedUpdates(e, t) }, flushBatchedUpdates: w, injection: { injectReconcileTransaction: function (e) { e || r("126"), x.ReactReconcileTransaction = e }, injectBatchingStrategy: function (e) { e || r("127"), "function" != typeof e.batchedUpdates && r("128"), "boolean" != typeof e.isBatchingUpdates && r("129"), m = e } }, asap: function (e, t) { l(m.isBatchingUpdates, "ReactUpdates.asap: Can't enqueue an asap callback in a context whereupdates are not being batched."), h.enqueue(e, t), d = !0 } }; e.exports = x }, function (e, t, n) { "use strict"; (function (t) { function n(e) { return e instanceof t || e instanceof Date || e instanceof RegExp } function r(e) { if (e instanceof t) { var n = t.alloc ? t.alloc(e.length) : new t(e.length); return e.copy(n), n } if (e instanceof Date) return new Date(e.getTime()); if (e instanceof RegExp) return new RegExp(e); throw new Error("Unexpected situation") } function o(e) { var t = []; return e.forEach((function (e, a) { "object" == typeof e && null !== e ? Array.isArray(e) ? t[a] = o(e) : n(e) ? t[a] = r(e) : t[a] = i({}, e) : t[a] = e })), t } function a(e, t) { return "__proto__" === t ? void 0 : e[t] } var i = e.exports = function () { if (arguments.length < 1 || "object" != typeof arguments[0]) return !1; if (arguments.length < 2) return arguments[0]; var e, t, s = arguments[0], u = Array.prototype.slice.call(arguments, 1); return u.forEach((function (u) { "object" != typeof u || null === u || Array.isArray(u) || Object.keys(u).forEach((function (c) { return t = a(s, c), (e = a(u, c)) === s ? void 0 : "object" != typeof e || null === e ? void (s[c] = e) : Array.isArray(e) ? void (s[c] = o(e)) : n(e) ? void (s[c] = r(e)) : "object" != typeof t || null === t || Array.isArray(t) ? void (s[c] = i({}, e)) : void (s[c] = i(t, e)) })) })), s } }).call(this, n(77).Buffer) }, function (e, t, n) { e.exports = n(686) }, function (e, t, n) { "use strict"; var r = n(1075), o = n(1076); function a() { this.protocol = null, this.slashes = null, this.auth = null, this.host = null, this.port = null, this.hostname = null, this.hash = null, this.search = null, this.query = null, this.pathname = null, this.path = null, this.href = null } t.parse = b, t.resolve = function (e, t) { return b(e, !1, !0).resolve(t) }, t.resolveObject = function (e, t) { return e ? b(e, !1, !0).resolveObject(t) : t }, t.format = function (e) { o.isString(e) && (e = b(e)); return e instanceof a ? e.format() : a.prototype.format.call(e) }, t.Url = a; var i = /^([a-z0-9.+-]+:)/i, s = /:[0-9]*$/, u = /^(\/\/?(?!\/)[^\?\s]*)(\?[^\s]*)?$/, c = ["{", "}", "|", "\\", "^", "`"].concat(["<", ">", '"', "`", " ", "\r", "\n", "\t"]), l = ["'"].concat(c), p = ["%", "/", "?", ";", "#"].concat(l), f = ["/", "?", "#"], h = /^[+a-z0-9A-Z_-]{0,63}$/, d = /^([+a-z0-9A-Z_-]{0,63})(.*)$/, m = { javascript: !0, "javascript:": !0 }, v = { javascript: !0, "javascript:": !0 }, g = { http: !0, https: !0, ftp: !0, gopher: !0, file: !0, "http:": !0, "https:": !0, "ftp:": !0, "gopher:": !0, "file:": !0 }, y = n(1077); function b(e, t, n) { if (e && o.isObject(e) && e instanceof a) return e; var r = new a; return r.parse(e, t, n), r } a.prototype.parse = function (e, t, n) { if (!o.isString(e)) throw new TypeError("Parameter 'url' must be a string, not " + typeof e); var a = e.indexOf("?"), s = -1 !== a && a < e.indexOf("#") ? "?" : "#", c = e.split(s); c[0] = c[0].replace(/\\/g, "/"); var b = e = c.join(s); if (b = b.trim(), !n && 1 === e.split("#").length) { var _ = u.exec(b); if (_) return this.path = b, this.href = b, this.pathname = _[1], _[2] ? (this.search = _[2], this.query = t ? y.parse(this.search.substr(1)) : this.search.substr(1)) : t && (this.search = "", this.query = {}), this } var w = i.exec(b); if (w) { var x = (w = w[0]).toLowerCase(); this.protocol = x, b = b.substr(w.length) } if (n || w || b.match(/^\/\/[^@\/]+@[^@\/]+/)) { var E = "//" === b.substr(0, 2); !E || w && v[w] || (b = b.substr(2), this.slashes = !0) } if (!v[w] && (E || w && !g[w])) { for (var S, C, A = -1, k = 0; k < f.length; k++) { -1 !== (O = b.indexOf(f[k])) && (-1 === A || O < A) && (A = O) } -1 !== (C = -1 === A ? b.lastIndexOf("@") : b.lastIndexOf("@", A)) && (S = b.slice(0, C), b = b.slice(C + 1), this.auth = decodeURIComponent(S)), A = -1; for (k = 0; k < p.length; k++) { var O; -1 !== (O = b.indexOf(p[k])) && (-1 === A || O < A) && (A = O) } -1 === A && (A = b.length), this.host = b.slice(0, A), b = b.slice(A), this.parseHost(), this.hostname = this.hostname || ""; var j = "[" === this.hostname[0] && "]" === this.hostname[this.hostname.length - 1]; if (!j) for (var T = this.hostname.split(/\./), I = (k = 0, T.length); k < I; k++) { var P = T[k]; if (P && !P.match(h)) { for (var N = "", M = 0, R = P.length; M < R; M++)P.charCodeAt(M) > 127 ? N += "x" : N += P[M]; if (!N.match(h)) { var D = T.slice(0, k), L = T.slice(k + 1), B = P.match(d); B && (D.push(B[1]), L.unshift(B[2])), L.length && (b = "/" + L.join(".") + b), this.hostname = D.join("."); break } } } this.hostname.length > 255 ? this.hostname = "" : this.hostname = this.hostname.toLowerCase(), j || (this.hostname = r.toASCII(this.hostname)); var F = this.port ? ":" + this.port : "", U = this.hostname || ""; this.host = U + F, this.href += this.host, j && (this.hostname = this.hostname.substr(1, this.hostname.length - 2), "/" !== b[0] && (b = "/" + b)) } if (!m[x]) for (k = 0, I = l.length; k < I; k++) { var q = l[k]; if (-1 !== b.indexOf(q)) { var z = encodeURIComponent(q); z === q && (z = escape(q)), b = b.split(q).join(z) } } var V = b.indexOf("#"); -1 !== V && (this.hash = b.substr(V), b = b.slice(0, V)); var W = b.indexOf("?"); if (-1 !== W ? (this.search = b.substr(W), this.query = b.substr(W + 1), t && (this.query = y.parse(this.query)), b = b.slice(0, W)) : t && (this.search = "", this.query = {}), b && (this.pathname = b), g[x] && this.hostname && !this.pathname && (this.pathname = "/"), this.pathname || this.search) { F = this.pathname || ""; var H = this.search || ""; this.path = F + H } return this.href = this.format(), this }, a.prototype.format = function () { var e = this.auth || ""; e && (e = (e = encodeURIComponent(e)).replace(/%3A/i, ":"), e += "@"); var t = this.protocol || "", n = this.pathname || "", r = this.hash || "", a = !1, i = ""; this.host ? a = e + this.host : this.hostname && (a = e + (-1 === this.hostname.indexOf(":") ? this.hostname : "[" + this.hostname + "]"), this.port && (a += ":" + this.port)), this.query && o.isObject(this.query) && Object.keys(this.query).length && (i = y.stringify(this.query)); var s = this.search || i && "?" + i || ""; return t && ":" !== t.substr(-1) && (t += ":"), this.slashes || (!t || g[t]) && !1 !== a ? (a = "//" + (a || ""), n && "/" !== n.charAt(0) && (n = "/" + n)) : a || (a = ""), r && "#" !== r.charAt(0) && (r = "#" + r), s && "?" !== s.charAt(0) && (s = "?" + s), t + a + (n = n.replace(/[?#]/g, (function (e) { return encodeURIComponent(e) }))) + (s = s.replace("#", "%23")) + r }, a.prototype.resolve = function (e) { return this.resolveObject(b(e, !1, !0)).format() }, a.prototype.resolveObject = function (e) { if (o.isString(e)) { var t = new a; t.parse(e, !1, !0), e = t } for (var n = new a, r = Object.keys(this), i = 0; i < r.length; i++) { var s = r[i]; n[s] = this[s] } if (n.hash = e.hash, "" === e.href) return n.href = n.format(), n; if (e.slashes && !e.protocol) { for (var u = Object.keys(e), c = 0; c < u.length; c++) { var l = u[c]; "protocol" !== l && (n[l] = e[l]) } return g[n.protocol] && n.hostname && !n.pathname && (n.path = n.pathname = "/"), n.href = n.format(), n } if (e.protocol && e.protocol !== n.protocol) { if (!g[e.protocol]) { for (var p = Object.keys(e), f = 0; f < p.length; f++) { var h = p[f]; n[h] = e[h] } return n.href = n.format(), n } if (n.protocol = e.protocol, e.host || v[e.protocol]) n.pathname = e.pathname; else { for (var d = (e.pathname || "").split("/"); d.length && !(e.host = d.shift());); e.host || (e.host = ""), e.hostname || (e.hostname = ""), "" !== d[0] && d.unshift(""), d.length < 2 && d.unshift(""), n.pathname = d.join("/") } if (n.search = e.search, n.query = e.query, n.host = e.host || "", n.auth = e.auth, n.hostname = e.hostname || e.host, n.port = e.port, n.pathname || n.search) { var m = n.pathname || "", y = n.search || ""; n.path = m + y } return n.slashes = n.slashes || e.slashes, n.href = n.format(), n } var b = n.pathname && "/" === n.pathname.charAt(0), _ = e.host || e.pathname && "/" === e.pathname.charAt(0), w = _ || b || n.host && e.pathname, x = w, E = n.pathname && n.pathname.split("/") || [], S = (d = e.pathname && e.pathname.split("/") || [], n.protocol && !g[n.protocol]); if (S && (n.hostname = "", n.port = null, n.host && ("" === E[0] ? E[0] = n.host : E.unshift(n.host)), n.host = "", e.protocol && (e.hostname = null, e.port = null, e.host && ("" === d[0] ? d[0] = e.host : d.unshift(e.host)), e.host = null), w = w && ("" === d[0] || "" === E[0])), _) n.host = e.host || "" === e.host ? e.host : n.host, n.hostname = e.hostname || "" === e.hostname ? e.hostname : n.hostname, n.search = e.search, n.query = e.query, E = d; else if (d.length) E || (E = []), E.pop(), E = E.concat(d), n.search = e.search, n.query = e.query; else if (!o.isNullOrUndefined(e.search)) { if (S) n.hostname = n.host = E.shift(), (j = !!(n.host && n.host.indexOf("@") > 0) && n.host.split("@")) && (n.auth = j.shift(), n.host = n.hostname = j.shift()); return n.search = e.search, n.query = e.query, o.isNull(n.pathname) && o.isNull(n.search) || (n.path = (n.pathname ? n.pathname : "") + (n.search ? n.search : "")), n.href = n.format(), n } if (!E.length) return n.pathname = null, n.search ? n.path = "/" + n.search : n.path = null, n.href = n.format(), n; for (var C = E.slice(-1)[0], A = (n.host || e.host || E.length > 1) && ("." === C || ".." === C) || "" === C, k = 0, O = E.length; O >= 0; O--)"." === (C = E[O]) ? E.splice(O, 1) : ".." === C ? (E.splice(O, 1), k++) : k && (E.splice(O, 1), k--); if (!w && !x) for (; k--; k)E.unshift(".."); !w || "" === E[0] || E[0] && "/" === E[0].charAt(0) || E.unshift(""), A && "/" !== E.join("/").substr(-1) && E.push(""); var j, T = "" === E[0] || E[0] && "/" === E[0].charAt(0); S && (n.hostname = n.host = T ? "" : E.length ? E.shift() : "", (j = !!(n.host && n.host.indexOf("@") > 0) && n.host.split("@")) && (n.auth = j.shift(), n.host = n.hostname = j.shift())); return (w = w || n.host && E.length) && !T && E.unshift(""), E.length ? n.pathname = E.join("/") : (n.pathname = null, n.path = null), o.isNull(n.pathname) && o.isNull(n.search) || (n.path = (n.pathname ? n.pathname : "") + (n.search ? n.search : "")), n.auth = e.auth || n.auth, n.slashes = n.slashes || e.slashes, n.href = n.format(), n }, a.prototype.parseHost = function () { var e = this.host, t = s.exec(e); t && (":" !== (t = t[0]) && (this.port = t.substr(1)), e = e.substr(0, e.length - t.length)), e && (this.hostname = e) } }, function (e, t, n) { "use strict"; n.r(t), n.d(t, "SHOW_AUTH_POPUP", (function () { return h })), n.d(t, "AUTHORIZE", (function () { return d })), n.d(t, "LOGOUT", (function () { return m })), n.d(t, "PRE_AUTHORIZE_OAUTH2", (function () { return v })), n.d(t, "AUTHORIZE_OAUTH2", (function () { return g })), n.d(t, "VALIDATE", (function () { return y })), n.d(t, "CONFIGURE_AUTH", (function () { return b })), n.d(t, "RESTORE_AUTHORIZATION", (function () { return _ })), n.d(t, "showDefinitions", (function () { return w })), n.d(t, "authorize", (function () { return x })), n.d(t, "authorizeWithPersistOption", (function () { return E })), n.d(t, "logout", (function () { return S })), n.d(t, "logoutWithPersistOption", (function () { return C })), n.d(t, "preAuthorizeImplicit", (function () { return A })), n.d(t, "authorizeOauth2", (function () { return k })), n.d(t, "authorizeOauth2WithPersistOption", (function () { return O })), n.d(t, "authorizePassword", (function () { return j })), n.d(t, "authorizeApplication", (function () { return T })), n.d(t, "authorizeAccessCodeWithFormParams", (function () { return I })), n.d(t, "authorizeAccessCodeWithBasicAuthentication", (function () { return P })), n.d(t, "authorizeRequest", (function () { return N })), n.d(t, "configureAuth", (function () { return M })), n.d(t, "restoreAuthorization", (function () { return R })), n.d(t, "persistAuthorizationIfNeeded", (function () { return D })); var r = n(19), o = n.n(r), a = n(22), i = n.n(a), s = n(32), u = n.n(s), c = n(98), l = n.n(c), p = n(27), f = n(5), h = "show_popup", d = "authorize", m = "logout", v = "pre_authorize_oauth2", g = "authorize_oauth2", y = "validate", b = "configure_auth", _ = "restore_authorization"; function w(e) { return { type: h, payload: e } } function x(e) { return { type: d, payload: e } } var E = function (e) { return function (t) { var n = t.authActions; n.authorize(e), n.persistAuthorizationIfNeeded() } }; function S(e) { return { type: m, payload: e } } var C = function (e) { return function (t) { var n = t.authActions; n.logout(e), n.persistAuthorizationIfNeeded() } }, A = function (e) { return function (t) { var n = t.authActions, r = t.errActions, o = e.auth, a = e.token, i = e.isValid, s = o.schema, c = o.name, l = s.get("flow"); delete p.a.swaggerUIRedirectOauth2, "accessCode" === l || i || r.newAuthErr({ authId: c, source: "auth", level: "warning", message: "Authorization may be unsafe, passed state was changed in server Passed state wasn't returned from auth server" }), a.error ? r.newAuthErr({ authId: c, source: "auth", level: "error", message: u()(a) }) : n.authorizeOauth2WithPersistOption({ auth: o, token: a }) } }; function k(e) { return { type: g, payload: e } } var O = function (e) { return function (t) { var n = t.authActions; n.authorizeOauth2(e), n.persistAuthorizationIfNeeded() } }, j = function (e) { return function (t) { var n = t.authActions, r = e.schema, o = e.name, a = e.username, s = e.password, u = e.passwordType, c = e.clientId, l = e.clientSecret, p = { grant_type: "password", scope: e.scopes.join(" "), username: a, password: s }, h = {}; switch (u) { case "request-body": !function (e, t, n) { t && i()(e, { client_id: t }); n && i()(e, { client_secret: n }) }(p, c, l); break; case "basic": h.Authorization = "Basic " + Object(f.a)(c + ":" + l); break; default: console.warn("Warning: invalid passwordType ".concat(u, " was passed, not including client id and secret")) }return n.authorizeRequest({ body: Object(f.b)(p), url: r.get("tokenUrl"), name: o, headers: h, query: {}, auth: e }) } }; var T = function (e) { return function (t) { var n = t.authActions, r = e.schema, o = e.scopes, a = e.name, i = e.clientId, s = e.clientSecret, u = { Authorization: "Basic " + Object(f.a)(i + ":" + s) }, c = { grant_type: "client_credentials", scope: o.join(" ") }; return n.authorizeRequest({ body: Object(f.b)(c), name: a, url: r.get("tokenUrl"), auth: e, headers: u }) } }, I = function (e) { var t = e.auth, n = e.redirectUrl; return function (e) { var r = e.authActions, o = t.schema, a = t.name, i = t.clientId, s = t.clientSecret, u = t.codeVerifier, c = { grant_type: "authorization_code", code: t.code, client_id: i, client_secret: s, redirect_uri: n, code_verifier: u }; return r.authorizeRequest({ body: Object(f.b)(c), name: a, url: o.get("tokenUrl"), auth: t }) } }, P = function (e) { var t = e.auth, n = e.redirectUrl; return function (e) { var r = e.authActions, o = t.schema, a = t.name, i = t.clientId, s = t.clientSecret, u = { Authorization: "Basic " + Object(f.a)(i + ":" + s) }, c = { grant_type: "authorization_code", code: t.code, client_id: i, redirect_uri: n }; return r.authorizeRequest({ body: Object(f.b)(c), name: a, url: o.get("tokenUrl"), auth: t, headers: u }) } }, N = function (e) { return function (t) { var n, r = t.fn, a = t.getConfigs, s = t.authActions, c = t.errActions, p = t.oas3Selectors, f = t.specSelectors, h = t.authSelectors, d = e.body, m = e.query, v = void 0 === m ? {} : m, g = e.headers, y = void 0 === g ? {} : g, b = e.name, _ = e.url, w = e.auth, x = (h.getConfigs() || {}).additionalQueryStringParams; if (f.isOAS3()) { var E = p.serverEffectiveValue(p.selectedServer()); n = l()(_, E, !0) } else n = l()(_, f.url(), !0); "object" === o()(x) && (n.query = i()({}, n.query, x)); var S = n.toString(), C = i()({ Accept: "application/json, text/plain, */*", "Content-Type": "application/x-www-form-urlencoded", "X-Requested-With": "XMLHttpRequest" }, y); r.fetch({ url: S, method: "post", headers: C, query: v, body: d, requestInterceptor: a().requestInterceptor, responseInterceptor: a().responseInterceptor }).then((function (e) { var t = JSON.parse(e.data), n = t && (t.error || ""), r = t && (t.parseError || ""); e.ok ? n || r ? c.newAuthErr({ authId: b, level: "error", source: "auth", message: u()(t) }) : s.authorizeOauth2WithPersistOption({ auth: w, token: t }) : c.newAuthErr({ authId: b, level: "error", source: "auth", message: e.statusText }) })).catch((function (e) { var t = new Error(e).message; if (e.response && e.response.data) { var n = e.response.data; try { var r = "string" == typeof n ? JSON.parse(n) : n; r.error && (t += ", error: ".concat(r.error)), r.error_description && (t += ", description: ".concat(r.error_description)) } catch (e) { } } c.newAuthErr({ authId: b, level: "error", source: "auth", message: t }) })) } }; function M(e) { return { type: b, payload: e } } function R(e) { return { type: _, payload: e } } var D = function () { return function (e) { var t = e.authSelectors; if ((0, e.getConfigs)().persistAuthorization) { var n = t.authorized(); localStorage.setItem("authorized", u()(n.toJS())) } } } }, function (e, t, n) { var r = n(1105); e.exports = function (e) { for (var t = 1; t < arguments.length; t++) { var n = null != arguments[t] ? Object(arguments[t]) : {}, o = Object.keys(n); "function" == typeof Object.getOwnPropertySymbols && (o = o.concat(Object.getOwnPropertySymbols(n).filter((function (e) { return Object.getOwnPropertyDescriptor(n, e).enumerable })))), o.forEach((function (t) { r(e, t, n[t]) })) } return e } }, function (e, t, n) { var r = n(238), o = n(149), a = n(39)("toStringTag"), i = "Arguments" == o(function () { return arguments }()); e.exports = r ? o : function (e) { var t, n, r; return void 0 === e ? "Undefined" : null === e ? "Null" : "string" == typeof (n = function (e, t) { try { return e[t] } catch (e) { } }(t = Object(e), a)) ? n : i ? o(t) : "Object" == (r = o(t)) && "function" == typeof t.callee ? "Arguments" : r } }, function (e, t, n) { var r = n(109), o = n(177), a = n(73), i = n(81), s = n(241), u = [].push, c = function (e) { var t = 1 == e, n = 2 == e, c = 3 == e, l = 4 == e, p = 6 == e, f = 7 == e, h = 5 == e || p; return function (d, m, v, g) { for (var y, b, _ = a(d), w = o(_), x = r(m, v, 3), E = i(w.length), S = 0, C = g || s, A = t ? C(d, E) : n || f ? C(d, 0) : void 0; E > S; S++)if ((h || S in w) && (b = x(y = w[S], S, _), e)) if (t) A[S] = b; else if (b) switch (e) { case 3: return !0; case 5: return y; case 6: return S; case 2: u.call(A, y) } else switch (e) { case 4: return !1; case 7: u.call(A, y) }return p ? -1 : c || l ? l : A } }; e.exports = { forEach: c(0), map: c(1), filter: c(2), some: c(3), every: c(4), find: c(5), findIndex: c(6), filterOut: c(7) } }, function (e, t, n) { "use strict"; e.exports = { current: null } }, function (e, t) { e.exports = function (e) { return null != e && "object" == typeof e } }, function (e, t) { var n, r, o = e.exports = {}; function a() { throw new Error("setTimeout has not been defined") } function i() { throw new Error("clearTimeout has not been defined") } function s(e) { if (n === setTimeout) return setTimeout(e, 0); if ((n === a || !n) && setTimeout) return n = setTimeout, setTimeout(e, 0); try { return n(e, 0) } catch (t) { try { return n.call(null, e, 0) } catch (t) { return n.call(this, e, 0) } } } !function () { try { n = "function" == typeof setTimeout ? setTimeout : a } catch (e) { n = a } try { r = "function" == typeof clearTimeout ? clearTimeout : i } catch (e) { r = i } }(); var u, c = [], l = !1, p = -1; function f() { l && u && (l = !1, u.length ? c = u.concat(c) : p = -1, c.length && h()) } function h() { if (!l) { var e = s(f); l = !0; for (var t = c.length; t;) { for (u = c, c = []; ++p < t;)u && u[p].run(); p = -1, t = c.length } u = null, l = !1, function (e) { if (r === clearTimeout) return clearTimeout(e); if ((r === i || !r) && clearTimeout) return r = clearTimeout, clearTimeout(e); try { r(e) } catch (t) { try { return r.call(null, e) } catch (t) { return r.call(this, e) } } }(e) } } function d(e, t) { this.fun = e, this.array = t } function m() { } o.nextTick = function (e) { var t = new Array(arguments.length - 1); if (arguments.length > 1) for (var n = 1; n < arguments.length; n++)t[n - 1] = arguments[n]; c.push(new d(e, t)), 1 !== c.length || l || s(h) }, d.prototype.run = function () { this.fun.apply(null, this.array) }, o.title = "browser", o.browser = !0, o.env = {}, o.argv = [], o.version = "", o.versions = {}, o.on = m, o.addListener = m, o.once = m, o.off = m, o.removeListener = m, o.removeAllListeners = m, o.emit = m, o.prependListener = m, o.prependOnceListener = m, o.listeners = function (e) { return [] }, o.binding = function (e) { throw new Error("process.binding is not supported") }, o.cwd = function () { return "/" }, o.chdir = function (e) { throw new Error("process.chdir is not supported") }, o.umask = function () { return 0 } }, function (e, t, n) { "use strict"; var r = n(40), o = n(124), a = n(83), i = (n(34), ["dispatchConfig", "_targetInst", "nativeEvent", "isDefaultPrevented", "isPropagationStopped", "_dispatchListeners", "_dispatchInstances"]), s = { type: null, target: null, currentTarget: a.thatReturnsNull, eventPhase: null, bubbles: null, cancelable: null, timeStamp: function (e) { return e.timeStamp || Date.now() }, defaultPrevented: null, isTrusted: null }; function u(e, t, n, r) { this.dispatchConfig = e, this._targetInst = t, this.nativeEvent = n; var o = this.constructor.Interface; for (var i in o) if (o.hasOwnProperty(i)) { 0; var s = o[i]; s ? this[i] = s(n) : "target" === i ? this.target = r : this[i] = n[i] } var u = null != n.defaultPrevented ? n.defaultPrevented : !1 === n.returnValue; return this.isDefaultPrevented = u ? a.thatReturnsTrue : a.thatReturnsFalse, this.isPropagationStopped = a.thatReturnsFalse, this } r(u.prototype, { preventDefault: function () { this.defaultPrevented = !0; var e = this.nativeEvent; e && (e.preventDefault ? e.preventDefault() : "unknown" != typeof e.returnValue && (e.returnValue = !1), this.isDefaultPrevented = a.thatReturnsTrue) }, stopPropagation: function () { var e = this.nativeEvent; e && (e.stopPropagation ? e.stopPropagation() : "unknown" != typeof e.cancelBubble && (e.cancelBubble = !0), this.isPropagationStopped = a.thatReturnsTrue) }, persist: function () { this.isPersistent = a.thatReturnsTrue }, isPersistent: a.thatReturnsFalse, destructor: function () { var e = this.constructor.Interface; for (var t in e) this[t] = null; for (var n = 0; n < i.length; n++)this[i[n]] = null } }), u.Interface = s, u.augmentClass = function (e, t) { var n = this, a = function () { }; a.prototype = n.prototype; var i = new a; r(i, e.prototype), e.prototype = i, e.prototype.constructor = e, e.Interface = r({}, n.Interface, t), e.augmentClass = n.augmentClass, o.addPoolingTo(e, o.fourArgumentPooler) }, o.addPoolingTo(u, o.fourArgumentPooler), e.exports = u }, function (e, t, n) { var r = n(406); e.exports = function (e) { return null == e ? "" : r(e) } }, function (e, t, n) { "use strict"; n.r(t), n.d(t, "lastError", (function () { return M })), n.d(t, "url", (function () { return R })), n.d(t, "specStr", (function () { return D })), n.d(t, "specSource", (function () { return L })), n.d(t, "specJson", (function () { return B })), n.d(t, "specResolved", (function () { return F })), n.d(t, "specResolvedSubtree", (function () { return U })), n.d(t, "specJsonWithResolvedSubtrees", (function () { return z })), n.d(t, "spec", (function () { return V })), n.d(t, "isOAS3", (function () { return W })), n.d(t, "info", (function () { return H })), n.d(t, "externalDocs", (function () { return J })), n.d(t, "version", (function () { return $ })), n.d(t, "semver", (function () { return K })), n.d(t, "paths", (function () { return Y })), n.d(t, "operations", (function () { return G })), n.d(t, "consumes", (function () { return Z })), n.d(t, "produces", (function () { return X })), n.d(t, "security", (function () { return Q })), n.d(t, "securityDefinitions", (function () { return ee })), n.d(t, "findDefinition", (function () { return te })), n.d(t, "definitions", (function () { return ne })), n.d(t, "basePath", (function () { return re })), n.d(t, "host", (function () { return oe })), n.d(t, "schemes", (function () { return ae })), n.d(t, "operationsWithRootInherited", (function () { return ie })), n.d(t, "tags", (function () { return se })), n.d(t, "tagDetails", (function () { return ue })), n.d(t, "operationsWithTags", (function () { return ce })), n.d(t, "taggedOperations", (function () { return le })), n.d(t, "responses", (function () { return pe })), n.d(t, "requests", (function () { return fe })), n.d(t, "mutatedRequests", (function () { return he })), n.d(t, "responseFor", (function () { return de })), n.d(t, "requestFor", (function () { return me })), n.d(t, "mutatedRequestFor", (function () { return ve })), n.d(t, "allowTryItOutFor", (function () { return ge })), n.d(t, "parameterWithMetaByIdentity", (function () { return ye })), n.d(t, "parameterInclusionSettingFor", (function () { return be })), n.d(t, "parameterWithMeta", (function () { return _e })), n.d(t, "operationWithMeta", (function () { return we })), n.d(t, "getParameter", (function () { return xe })), n.d(t, "hasHost", (function () { return Ee })), n.d(t, "parameterValues", (function () { return Se })), n.d(t, "parametersIncludeIn", (function () { return Ce })), n.d(t, "parametersIncludeType", (function () { return Ae })), n.d(t, "contentTypeValues", (function () { return ke })), n.d(t, "currentProducesFor", (function () { return Oe })), n.d(t, "producesOptionsFor", (function () { return je })), n.d(t, "consumesOptionsFor", (function () { return Te })), n.d(t, "operationScheme", (function () { return Ie })), n.d(t, "canExecuteScheme", (function () { return Pe })), n.d(t, "validateBeforeExecute", (function () { return Ne })), n.d(t, "getOAS3RequiredRequestBodyContentType", (function () { return Me })), n.d(t, "isMediaTypeSchemaPropertiesEqual", (function () { return Re })); var r = n(13), o = n.n(r), a = n(16), i = n.n(a), s = n(37), u = n.n(s), c = n(212), l = n.n(c), p = n(21), f = n.n(p), h = n(67), d = n.n(h), m = n(12), v = n.n(m), g = n(4), y = n.n(g), b = n(14), _ = n.n(b), w = n(18), x = n.n(w), E = n(23), S = n.n(E), C = n(2), A = n.n(C), k = n(15), O = n.n(k), j = n(20), T = n(5), I = n(1), P = ["get", "put", "post", "delete", "options", "head", "patch", "trace"], N = function (e) { return e || Object(I.Map)() }, M = Object(j.a)(N, (function (e) { return e.get("lastError") })), R = Object(j.a)(N, (function (e) { return e.get("url") })), D = Object(j.a)(N, (function (e) { return e.get("spec") || "" })), L = Object(j.a)(N, (function (e) { return e.get("specSource") || "not-editor" })), B = Object(j.a)(N, (function (e) { return e.get("json", Object(I.Map)()) })), F = Object(j.a)(N, (function (e) { return e.get("resolved", Object(I.Map)()) })), U = function (e, t) { var n; return e.getIn(A()(n = ["resolvedSubtrees"]).call(n, O()(t)), void 0) }, q = function e(t, n) { return I.Map.isMap(t) && I.Map.isMap(n) ? n.get("$$ref") ? n : Object(I.OrderedMap)().mergeWith(e, t, n) : n }, z = Object(j.a)(N, (function (e) { return Object(I.OrderedMap)().mergeWith(q, e.get("json"), e.get("resolvedSubtrees")) })), V = function (e) { return B(e) }, W = Object(j.a)(V, (function () { return !1 })), H = Object(j.a)(V, (function (e) { return De(e && e.get("info")) })), J = Object(j.a)(V, (function (e) { return De(e && e.get("externalDocs")) })), $ = Object(j.a)(H, (function (e) { return e && e.get("version") })), K = Object(j.a)($, (function (e) { var t; return S()(t = /v?([0-9]*)\.([0-9]*)\.([0-9]*)/i.exec(e)).call(t, 1) })), Y = Object(j.a)(z, (function (e) { return e.get("paths") })), G = Object(j.a)(Y, (function (e) { if (!e || e.size < 1) return Object(I.List)(); var t = Object(I.List)(); return e && x()(e) ? (x()(e).call(e, (function (e, n) { if (!e || !x()(e)) return {}; x()(e).call(e, (function (e, r) { var o; _()(P).call(P, r) < 0 || (t = t.push(Object(I.fromJS)({ path: n, method: r, operation: e, id: A()(o = "".concat(r, "-")).call(o, n) }))) })) })), t) : Object(I.List)() })), Z = Object(j.a)(V, (function (e) { return Object(I.Set)(e.get("consumes")) })), X = Object(j.a)(V, (function (e) { return Object(I.Set)(e.get("produces")) })), Q = Object(j.a)(V, (function (e) { return e.get("security", Object(I.List)()) })), ee = Object(j.a)(V, (function (e) { return e.get("securityDefinitions") })), te = function (e, t) { var n = e.getIn(["resolvedSubtrees", "definitions", t], null), r = e.getIn(["json", "definitions", t], null); return n || r || null }, ne = Object(j.a)(V, (function (e) { var t = e.get("definitions"); return I.Map.isMap(t) ? t : Object(I.Map)() })), re = Object(j.a)(V, (function (e) { return e.get("basePath") })), oe = Object(j.a)(V, (function (e) { return e.get("host") })), ae = Object(j.a)(V, (function (e) { return e.get("schemes", Object(I.Map)()) })), ie = Object(j.a)(G, Z, X, (function (e, t, n) { return y()(e).call(e, (function (e) { return e.update("operation", (function (e) { if (e) { if (!I.Map.isMap(e)) return; return e.withMutations((function (e) { return e.get("consumes") || e.update("consumes", (function (e) { return Object(I.Set)(e).merge(t) })), e.get("produces") || e.update("produces", (function (e) { return Object(I.Set)(e).merge(n) })), e })) } return Object(I.Map)() })) })) })), se = Object(j.a)(V, (function (e) { var t = e.get("tags", Object(I.List)()); return I.List.isList(t) ? v()(t).call(t, (function (e) { return I.Map.isMap(e) })) : Object(I.List)() })), ue = function (e, t) { var n, r = se(e) || Object(I.List)(); return d()(n = v()(r).call(r, I.Map.isMap)).call(n, (function (e) { return e.get("name") === t }), Object(I.Map)()) }, ce = Object(j.a)(ie, se, (function (e, t) { return f()(e).call(e, (function (e, t) { var n = Object(I.Set)(t.getIn(["operation", "tags"])); return n.count() < 1 ? e.update("default", Object(I.List)(), (function (e) { return e.push(t) })) : f()(n).call(n, (function (e, n) { return e.update(n, Object(I.List)(), (function (e) { return e.push(t) })) }), e) }), f()(t).call(t, (function (e, t) { return e.set(t.get("name"), Object(I.List)()) }), Object(I.OrderedMap)())) })), le = function (e) { return function (t) { var n, r = (0, t.getConfigs)(), o = r.tagsSorter, a = r.operationsSorter; return y()(n = ce(e).sortBy((function (e, t) { return t }), (function (e, t) { var n = "function" == typeof o ? o : T.I.tagsSorter[o]; return n ? n(e, t) : null }))).call(n, (function (t, n) { var r = "function" == typeof a ? a : T.I.operationsSorter[a], o = r ? l()(t).call(t, r) : t; return Object(I.Map)({ tagDetails: ue(e, n), operations: o }) })) } }, pe = Object(j.a)(N, (function (e) { return e.get("responses", Object(I.Map)()) })), fe = Object(j.a)(N, (function (e) { return e.get("requests", Object(I.Map)()) })), he = Object(j.a)(N, (function (e) { return e.get("mutatedRequests", Object(I.Map)()) })), de = function (e, t, n) { return pe(e).getIn([t, n], null) }, me = function (e, t, n) { return fe(e).getIn([t, n], null) }, ve = function (e, t, n) { return he(e).getIn([t, n], null) }, ge = function () { return !0 }, ye = function (e, t, n) { var r, o, a = z(e).getIn(A()(r = ["paths"]).call(r, O()(t), ["parameters"]), Object(I.OrderedMap)()), i = e.getIn(A()(o = ["meta", "paths"]).call(o, O()(t), ["parameters"]), Object(I.OrderedMap)()), s = y()(a).call(a, (function (e) { var t, r, o, a = i.get(A()(t = "".concat(n.get("in"), ".")).call(t, n.get("name"))), s = i.get(A()(r = A()(o = "".concat(n.get("in"), ".")).call(o, n.get("name"), ".hash-")).call(r, n.hashCode())); return Object(I.OrderedMap)().merge(e, a, s) })); return d()(s).call(s, (function (e) { return e.get("in") === n.get("in") && e.get("name") === n.get("name") }), Object(I.OrderedMap)()) }, be = function (e, t, n, r) { var o, a, i = A()(o = "".concat(r, ".")).call(o, n); return e.getIn(A()(a = ["meta", "paths"]).call(a, O()(t), ["parameter_inclusions", i]), !1) }, _e = function (e, t, n, r) { var o, a = z(e).getIn(A()(o = ["paths"]).call(o, O()(t), ["parameters"]), Object(I.OrderedMap)()), i = d()(a).call(a, (function (e) { return e.get("in") === r && e.get("name") === n }), Object(I.OrderedMap)()); return ye(e, t, i) }, we = function (e, t, n) { var r, o = z(e).getIn(["paths", t, n], Object(I.OrderedMap)()), a = e.getIn(["meta", "paths", t, n], Object(I.OrderedMap)()), i = y()(r = o.get("parameters", Object(I.List)())).call(r, (function (r) { return ye(e, [t, n], r) })); return Object(I.OrderedMap)().merge(o, a).set("parameters", i) }; function xe(e, t, n, r) { var o; t = t || []; var a = e.getIn(A()(o = ["meta", "paths"]).call(o, O()(t), ["parameters"]), Object(I.fromJS)([])); return d()(a).call(a, (function (e) { return I.Map.isMap(e) && e.get("name") === n && e.get("in") === r })) || Object(I.Map)() } var Ee = Object(j.a)(V, (function (e) { var t = e.get("host"); return "string" == typeof t && t.length > 0 && "/" !== t[0] })); function Se(e, t, n) { var r; t = t || []; var o = we.apply(void 0, A()(r = [e]).call(r, O()(t))).get("parameters", Object(I.List)()); return f()(o).call(o, (function (e, t) { var r = n && "body" === t.get("in") ? t.get("value_xml") : t.get("value"); return e.set(Object(T.B)(t, { allowHashes: !1 }), r) }), Object(I.fromJS)({})) } function Ce(e) { var t = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : ""; if (I.List.isList(e)) return u()(e).call(e, (function (e) { return I.Map.isMap(e) && e.get("in") === t })) } function Ae(e) { var t = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : ""; if (I.List.isList(e)) return u()(e).call(e, (function (e) { return I.Map.isMap(e) && e.get("type") === t })) } function ke(e, t) { var n, r; t = t || []; var o = z(e).getIn(A()(n = ["paths"]).call(n, O()(t)), Object(I.fromJS)({})), a = e.getIn(A()(r = ["meta", "paths"]).call(r, O()(t)), Object(I.fromJS)({})), i = Oe(e, t), s = o.get("parameters") || new I.List, u = a.get("consumes_value") ? a.get("consumes_value") : Ae(s, "file") ? "multipart/form-data" : Ae(s, "formData") ? "application/x-www-form-urlencoded" : void 0; return Object(I.fromJS)({ requestContentType: u, responseContentType: i }) } function Oe(e, t) { var n, r; t = t || []; var o = z(e).getIn(A()(n = ["paths"]).call(n, O()(t)), null); if (null !== o) { var a = e.getIn(A()(r = ["meta", "paths"]).call(r, O()(t), ["produces_value"]), null), i = o.getIn(["produces", 0], null); return a || i || "application/json" } } function je(e, t) { var n; t = t || []; var r = z(e), o = r.getIn(A()(n = ["paths"]).call(n, O()(t)), null); if (null !== o) { var a = t, s = i()(a, 1)[0], u = o.get("produces", null), c = r.getIn(["paths", s, "produces"], null), l = r.getIn(["produces"], null); return u || c || l } } function Te(e, t) { var n; t = t || []; var r = z(e), o = r.getIn(A()(n = ["paths"]).call(n, O()(t)), null); if (null !== o) { var a = t, s = i()(a, 1)[0], u = o.get("consumes", null), c = r.getIn(["paths", s, "consumes"], null), l = r.getIn(["consumes"], null); return u || c || l } } var Ie = function (e, t, n) { var r = e.get("url").match(/^([a-z][a-z0-9+\-.]*):/), a = o()(r) ? r[1] : null; return e.getIn(["scheme", t, n]) || e.getIn(["scheme", "_defaultScheme"]) || a || "" }, Pe = function (e, t, n) { var r; return _()(r = ["http", "https"]).call(r, Ie(e, t, n)) > -1 }, Ne = function (e, t) { var n; t = t || []; var r = e.getIn(A()(n = ["meta", "paths"]).call(n, O()(t), ["parameters"]), Object(I.fromJS)([])), o = !0; return x()(r).call(r, (function (e) { var t = e.get("errors"); t && t.count() && (o = !1) })), o }, Me = function (e, t) { var n, r, o = { requestBody: !1, requestContentType: {} }, a = e.getIn(A()(n = ["resolvedSubtrees", "paths"]).call(n, O()(t), ["requestBody"]), Object(I.fromJS)([])); return a.size < 1 || (a.getIn(["required"]) && (o.requestBody = a.getIn(["required"])), x()(r = a.getIn(["content"]).entrySeq()).call(r, (function (e) { var t = e[0]; if (e[1].getIn(["schema", "required"])) { var n = e[1].getIn(["schema", "required"]).toJS(); o.requestContentType[t] = n } }))), o }, Re = function (e, t, n, r) { var o; if ((n || r) && n === r) return !0; var a = e.getIn(A()(o = ["resolvedSubtrees", "paths"]).call(o, O()(t), ["requestBody", "content"]), Object(I.fromJS)([])); if (a.size < 2 || !n || !r) return !1; var i = a.getIn([n, "schema", "properties"], Object(I.fromJS)([])), s = a.getIn([r, "schema", "properties"], Object(I.fromJS)([])); return !!i.equals(s) }; function De(e) { return I.Map.isMap(e) ? e : new I.Map } }, function (e, t, n) { "use strict"; (function (t) { var r = n(915), o = n(916), a = /^[A-Za-z][A-Za-z0-9+-.]*:\/\//, i = /^([a-z][a-z0-9.+-]*:)?(\/\/)?([\S\s]*)/i, s = new RegExp("^[\\x09\\x0A\\x0B\\x0C\\x0D\\x20\\xA0\\u1680\\u180E\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200A\\u202F\\u205F\\u3000\\u2028\\u2029\\uFEFF]+"); function u(e) { return (e || "").toString().replace(s, "") } var c = [["#", "hash"], ["?", "query"], function (e) { return e.replace("\\", "/") }, ["/", "pathname"], ["@", "auth", 1], [NaN, "host", void 0, 1, 1], [/:(\d+)$/, "port", void 0, 1], [NaN, "hostname", void 0, 1, 1]], l = { hash: 1, query: 1 }; function p(e) { var n, r = ("undefined" != typeof window ? window : void 0 !== t ? t : "undefined" != typeof self ? self : {}).location || {}, o = {}, i = typeof (e = e || r); if ("blob:" === e.protocol) o = new h(unescape(e.pathname), {}); else if ("string" === i) for (n in o = new h(e, {}), l) delete o[n]; else if ("object" === i) { for (n in e) n in l || (o[n] = e[n]); void 0 === o.slashes && (o.slashes = a.test(e.href)) } return o } function f(e) { e = u(e); var t = i.exec(e); return { protocol: t[1] ? t[1].toLowerCase() : "", slashes: !!t[2], rest: t[3] } } function h(e, t, n) { if (e = u(e), !(this instanceof h)) return new h(e, t, n); var a, i, s, l, d, m, v = c.slice(), g = typeof t, y = this, b = 0; for ("object" !== g && "string" !== g && (n = t, t = null), n && "function" != typeof n && (n = o.parse), t = p(t), a = !(i = f(e || "")).protocol && !i.slashes, y.slashes = i.slashes || a && t.slashes, y.protocol = i.protocol || t.protocol || "", e = i.rest, i.slashes || (v[3] = [/(.*)/, "pathname"]); b < v.length; b++)"function" != typeof (l = v[b]) ? (s = l[0], m = l[1], s != s ? y[m] = e : "string" == typeof s ? ~(d = e.indexOf(s)) && ("number" == typeof l[2] ? (y[m] = e.slice(0, d), e = e.slice(d + l[2])) : (y[m] = e.slice(d), e = e.slice(0, d))) : (d = s.exec(e)) && (y[m] = d[1], e = e.slice(0, d.index)), y[m] = y[m] || a && l[3] && t[m] || "", l[4] && (y[m] = y[m].toLowerCase())) : e = l(e); n && (y.query = n(y.query)), a && t.slashes && "/" !== y.pathname.charAt(0) && ("" !== y.pathname || "" !== t.pathname) && (y.pathname = function (e, t) { if ("" === e) return t; for (var n = (t || "/").split("/").slice(0, -1).concat(e.split("/")), r = n.length, o = n[r - 1], a = !1, i = 0; r--;)"." === n[r] ? n.splice(r, 1) : ".." === n[r] ? (n.splice(r, 1), i++) : i && (0 === r && (a = !0), n.splice(r, 1), i--); return a && n.unshift(""), "." !== o && ".." !== o || n.push(""), n.join("/") }(y.pathname, t.pathname)), r(y.port, y.protocol) || (y.host = y.hostname, y.port = ""), y.username = y.password = "", y.auth && (l = y.auth.split(":"), y.username = l[0] || "", y.password = l[1] || ""), y.origin = y.protocol && y.host && "file:" !== y.protocol ? y.protocol + "//" + y.host : "null", y.href = y.toString() } h.prototype = { set: function (e, t, n) { var a = this; switch (e) { case "query": "string" == typeof t && t.length && (t = (n || o.parse)(t)), a[e] = t; break; case "port": a[e] = t, r(t, a.protocol) ? t && (a.host = a.hostname + ":" + t) : (a.host = a.hostname, a[e] = ""); break; case "hostname": a[e] = t, a.port && (t += ":" + a.port), a.host = t; break; case "host": a[e] = t, /:\d+$/.test(t) ? (t = t.split(":"), a.port = t.pop(), a.hostname = t.join(":")) : (a.hostname = t, a.port = ""); break; case "protocol": a.protocol = t.toLowerCase(), a.slashes = !n; break; case "pathname": case "hash": if (t) { var i = "pathname" === e ? "/" : "#"; a[e] = t.charAt(0) !== i ? i + t : t } else a[e] = t; break; default: a[e] = t }for (var s = 0; s < c.length; s++) { var u = c[s]; u[4] && (a[u[1]] = a[u[1]].toLowerCase()) } return a.origin = a.protocol && a.host && "file:" !== a.protocol ? a.protocol + "//" + a.host : "null", a.href = a.toString(), a }, toString: function (e) { e && "function" == typeof e || (e = o.stringify); var t, n = this, r = n.protocol; r && ":" !== r.charAt(r.length - 1) && (r += ":"); var a = r + (n.slashes ? "//" : ""); return n.username && (a += n.username, n.password && (a += ":" + n.password), a += "@"), a += n.host + n.pathname, (t = "object" == typeof n.query ? e(n.query) : n.query) && (a += "?" !== t.charAt(0) ? "?" + t : t), n.hash && (a += n.hash), a } }, h.extractProtocol = f, h.location = p, h.trimLeft = u, h.qs = o, e.exports = h }).call(this, n(55)) }, function (e, t) { e.exports = !0 }, function (e, t, n) { "use strict"; var r = n(363).charAt, o = n(82), a = n(236), i = "String Iterator", s = o.set, u = o.getterFor(i); a(String, "String", (function (e) { s(this, { type: i, string: String(e), index: 0 }) }), (function () { var e, t = u(this), n = t.string, o = t.index; return o >= n.length ? { value: void 0, done: !0 } : (e = r(n, o), t.index += e.length, { value: e, done: !1 }) })) }, function (e, t, n) { var r = n(238), o = n(71).f, a = n(70), i = n(52), s = n(559), u = n(39)("toStringTag"); e.exports = function (e, t, n, c) { if (e) { var l = n ? e : e.prototype; i(l, u) || o(l, u, { configurable: !0, value: t }), c && !r && a(l, "toString", s) } } }, function (e, t, n) { "use strict"; e.exports = function (e) { if ("function" != typeof e) throw new TypeError(e + " is not a function"); return e } }, function (e, t, n) { e.exports = n(636) }, function (e, t, n) { e.exports = n(869) }, function (e, t, n) { "use strict"; n.r(t), n.d(t, "UPDATE_LAYOUT", (function () { return o })), n.d(t, "UPDATE_FILTER", (function () { return a })), n.d(t, "UPDATE_MODE", (function () { return i })), n.d(t, "SHOW", (function () { return s })), n.d(t, "updateLayout", (function () { return u })), n.d(t, "updateFilter", (function () { return c })), n.d(t, "show", (function () { return l })), n.d(t, "changeMode", (function () { return p })); var r = n(5), o = "layout_update_layout", a = "layout_update_filter", i = "layout_update_mode", s = "layout_show"; function u(e) { return { type: o, payload: e } } function c(e) { return { type: a, payload: e } } function l(e) { var t = !(arguments.length > 1 && void 0 !== arguments[1]) || arguments[1]; return e = Object(r.w)(e), { type: s, payload: { thing: e, shown: t } } } function p(e) { var t = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : ""; return e = Object(r.w)(e), { type: i, payload: { thing: e, mode: t } } } }, function (e, t, n) { var r = n(421), o = n(161), a = n(193), i = n(54), s = n(117), u = n(194), c = n(160), l = n(252), p = Object.prototype.hasOwnProperty; e.exports = function (e) { if (null == e) return !0; if (s(e) && (i(e) || "string" == typeof e || "function" == typeof e.splice || u(e) || l(e) || a(e))) return !e.length; var t = o(e); if ("[object Map]" == t || "[object Set]" == t) return !e.size; if (c(e)) return !r(e).length; for (var n in e) if (p.call(e, n)) return !1; return !0 } }, function (e, t, n) { var r = n(49), o = n(176), a = n(108), i = n(69), s = n(178), u = n(52), c = n(357), l = Object.getOwnPropertyDescriptor; t.f = r ? l : function (e, t) { if (e = i(e), t = s(t, !0), c) try { return l(e, t) } catch (e) { } if (u(e, t)) return a(!o.f.call(e, t), e[t]) } }, function (e, t) { e.exports = function (e, t) { return { enumerable: !(1 & e), configurable: !(2 & e), writable: !(4 & e), value: t } } }, function (e, t, n) { var r = n(80); e.exports = function (e, t, n) { if (r(e), void 0 === t) return e; switch (n) { case 0: return function () { return e.call(t) }; case 1: return function (n) { return e.call(t, n) }; case 2: return function (n, r) { return e.call(t, n, r) }; case 3: return function (n, r, o) { return e.call(t, n, r, o) } }return function () { return e.apply(t, arguments) } } }, function (e, t, n) { var r, o = n(53), a = n(237), i = n(231), s = n(152), u = n(369), c = n(228), l = n(180), p = l("IE_PROTO"), f = function () { }, h = function (e) { return "