Compare commits
38 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4cf35f7294 | ||
|
|
94c77d151b | ||
|
|
7f600e2b4b | ||
|
|
c809d0ba87 | ||
|
|
50f038ec89 | ||
|
|
9199a255a2 | ||
|
|
d324537b47 | ||
|
|
d0c05685f7 | ||
|
|
1063c930b5 | ||
|
|
79cbd44366 | ||
|
|
7fdac1c5cb | ||
|
|
0c0cf72ebb | ||
|
|
8e2fe175ed | ||
|
|
d1cff037c9 | ||
|
|
fc88a2fafa | ||
|
|
45fcceb056 | ||
|
|
7043477038 | ||
|
|
7dd685cf54 | ||
|
|
5f5e4969c0 | ||
|
|
8a53fd19e9 | ||
|
|
baf4714c36 | ||
|
|
7ba9ac7a5b | ||
|
|
85b8f26e8e | ||
|
|
594a0f1410 | ||
|
|
d317d757d7 | ||
|
|
fdf0ba6318 | ||
|
|
15bf7de5fa | ||
|
|
d3402b058e | ||
|
|
e7dfdd4031 | ||
|
|
b2dd7b6364 | ||
|
|
9bd6d9abbf | ||
|
|
cd14428fea | ||
|
|
19d9f03c2b | ||
|
|
0d57e72bbf | ||
|
|
329516a61b | ||
|
|
d566869589 | ||
|
|
9cb8d8e6c7 | ||
|
|
9de3c57e5d |
@@ -1,8 +1,7 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<Version>3.0.0.24</Version>
|
||||
<Version>3.0.1.0</Version>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
|
||||
<Authors>Diego</Authors>
|
||||
<Product>ThingsGateway</Product>
|
||||
<Copyright>© 2023-present Diego</Copyright>
|
||||
|
||||
@@ -32,7 +32,6 @@ internal class Program
|
||||
AppDomain.CurrentDomain.UnhandledException += (sender, error) =>
|
||||
{
|
||||
};
|
||||
|
||||
app.Run();
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
|
||||
<ApplicationIcon>favicon.ico</ApplicationIcon>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -28,5 +29,18 @@
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<Content Update="wwwroot\favicon.ico">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\favicon.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\index.html">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
|
||||
</Project>
|
||||
|
||||
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
@@ -26,10 +26,10 @@
|
||||
<MTextField Class="ma-1" Style="max-width:100px" Label="端口" Dense Outlined HideDetails="@("auto")" @bind-Value=@port />
|
||||
|
||||
<MButton Class="ma-1" OnClick=@Connect Color="primary">
|
||||
连接
|
||||
启动
|
||||
</MButton>
|
||||
<MButton Class="ma-1" OnClick=@DisConnect Color="red">
|
||||
断开
|
||||
停止
|
||||
</MButton>
|
||||
|
||||
|
||||
|
||||
@@ -207,19 +207,40 @@ public partial class MainLayout
|
||||
]
|
||||
},
|
||||
{
|
||||
"Title": "GasCustom",
|
||||
"Title": "HZW_QTJC_01",
|
||||
"Children": [
|
||||
{
|
||||
"Href": "/GasCustomSerial",
|
||||
"Title": "GasCustomSerial"
|
||||
"Href": "/HZW_QTJC_01Serial",
|
||||
"Title": "HZW_QTJC_01Serial"
|
||||
},
|
||||
{
|
||||
"Href": "/GasCustomSerialOverTcp",
|
||||
"Title": "GasCustomSerialOverTcp"
|
||||
"Href": "/HZW_QTJC_01SerialOverTcp",
|
||||
"Title": "HZW_QTJC_01SerialOverTcp"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
},
|
||||
{
|
||||
"Title": "LQTCP",
|
||||
"Children": [
|
||||
{
|
||||
"Href": "/LQTCP",
|
||||
"Title": "LQTCP"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Title": "KELID2008",
|
||||
"Children": [
|
||||
{
|
||||
"Href": "/KELID2008",
|
||||
"Title": "KELID2008"
|
||||
},
|
||||
{
|
||||
"Href": "/KELID2008OverTcp",
|
||||
"Title": "KELID2008OverTcp"
|
||||
}
|
||||
]
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Razor">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(SolutionName)'=='ThingsGateway - Pro'">
|
||||
<DefineConstants>Pro</DefineConstants>
|
||||
</PropertyGroup>
|
||||
<ItemGroup Condition="'$(SolutionName)'=='ThingsGateway - Pro'">
|
||||
|
||||
|
||||
<ItemGroup Condition="'$(SolutionName)'=='ThingsGateway - Pro' AND '$(Configuration)' == 'Debug'">
|
||||
|
||||
<Compile Include="..\..\PluginPro\ThingsGateway.Plugin.Melsec\Page\QnA3E_BinaryDebugPage.razor.cs" Link="Pages\Melsec\QnA3E_BinaryDebugPage.razor.cs" />
|
||||
<Content Include="..\..\PluginPro\ThingsGateway.Plugin.Melsec\Page\QnA3E_BinaryDebugPage.razor" Link="Pages\Melsec\QnA3E_BinaryDebugPage.razor" />
|
||||
<ProjectReference Include="..\..\FoundationPro\ThingsGateway.Foundation.Adapter.Melsec\ThingsGateway.Foundation.Adapter.Melsec.csproj" />
|
||||
|
||||
|
||||
|
||||
|
||||
<Compile Include="..\..\PluginPro\ThingsGateway.Plugin.AllenBradleyCip\Page\AllenBradleyCipTcpDebugPage.razor.cs" Link="Pages\ABCIP\AllenBradleyCipTcpDebugPage.razor.cs" />
|
||||
<Content Include="..\..\PluginPro\ThingsGateway.Plugin.AllenBradleyCip\Page\AllenBradleyCipTcpDebugPage.razor" Link="Pages\ABCIP\AllenBradleyCipTcpDebugPage.razor" />
|
||||
<ProjectReference Include="..\..\FoundationPro\ThingsGateway.Foundation.Adapter.AllenBradleyCip\ThingsGateway.Foundation.Adapter.AllenBradleyCip.csproj" />
|
||||
@@ -46,13 +47,25 @@
|
||||
<ProjectReference Include="..\..\PluginProAF2021\ThingsGateway.Foundation.Adapter.HZW_QTJC_01\ThingsGateway.Foundation.Adapter.HZW_QTJC_01.csproj" />
|
||||
|
||||
|
||||
|
||||
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(SolutionName)'=='ThingsGateway - Pro' ">
|
||||
<Compile Include="..\..\PluginProAF2021\ThingsGateway.Plugin.LQTCP\Page\LQTCPDebugPage.razor.cs" Link="Pages\LQTCP\LQTCPDebugPage.razor.cs" />
|
||||
<Content Include="..\..\PluginProAF2021\ThingsGateway.Plugin.LQTCP\Page\LQTCPDebugPage.razor" Link="Pages\LQTCP\LQTCPDebugPage.razor" />
|
||||
<ProjectReference Include="..\..\PluginProAF2021\ThingsGateway.Foundation.Adapter.LQTCP\ThingsGateway.Foundation.Adapter.LQTCP.csproj" />
|
||||
|
||||
|
||||
<Compile Include="..\..\PluginProAF2021\ThingsGateway.Plugin.KELID2008\Page\KELID2008DebugPage.razor.cs" Link="Pages\KELID2008\KELID2008DebugPage.razor.cs" />
|
||||
<Compile Include="..\..\PluginProAF2021\ThingsGateway.Plugin.KELID2008\Page\KELID2008OverTcpDebugPage.razor.cs" Link="Pages\KELID2008\KELID2008OverTcpDebugPage.razor.cs" />
|
||||
<Content Include="..\..\PluginProAF2021\ThingsGateway.Plugin.KELID2008\Page\KELID2008DebugPage.razor" Link="Pages\KELID2008\KELID2008DebugPage.razor" />
|
||||
<Content Include="..\..\PluginProAF2021\ThingsGateway.Plugin.KELID2008\Page\KELID2008OverTcpDebugPage.razor" Link="Pages\KELID2008\KELID2008OverTcpDebugPage.razor" />
|
||||
<ProjectReference Include="..\..\PluginProAF2021\ThingsGateway.Foundation.Adapter.KELID2008\ThingsGateway.Foundation.Adapter.KELID2008.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="..\..\Plugin\ThingsGateway.Plugin.DLT645\Page\DLT645_2007DebugPage.razor.cs" Link="Pages\DLT645\DLT645_2007DebugPage.razor.cs" />
|
||||
|
||||
<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Mqtt\MqttRpcNameVaueWithId.cs" Link="Pages\Mqtt\MqttRpcNameVaueWithId.cs" />
|
||||
<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Mqtt\Page\MqttClientDebugPage.razor.cs" Link="Pages\Mqtt\MqttClientDebugPage.razor.cs" />
|
||||
<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Mqtt\Page\MqttClientPage.razor.cs" Link="Pages\Mqtt\MqttClientPage.razor.cs" />
|
||||
@@ -60,11 +73,18 @@
|
||||
<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Mqtt\RpcClass\MqttRpcClientExtensions.cs" Link="Pages\Mqtt\MqttRpcClientExtensions.cs" />
|
||||
<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Mqtt\RpcClass\MqttRpcTopicPair.cs" Link="Pages\Mqtt\MqttRpcTopicPair.cs" />
|
||||
<Compile Include="..\..\Web\ThingsGateway.Gateway.Application\Workers\ManageGateway\MqttLoggerExtensions.cs" Link="Pages\Mqtt\MqttLoggerExtensions.cs" />
|
||||
<Content Include="..\..\Plugin\ThingsGateway.Plugin.Mqtt\Page\MqttClientDebugPage.razor" Link="Pages\Mqtt\MqttClientDebugPage.razor" />
|
||||
<Content Include="..\..\Plugin\ThingsGateway.Plugin.Mqtt\Page\MqttClientPage.razor" Link="Pages\Mqtt\MqttClientPage.razor" />
|
||||
<PackageReference Include="MQTTnet" Version="4.3.1.873" />
|
||||
|
||||
|
||||
<Compile Include="..\..\Plugin\ThingsGateway.Plugin.DLT645\Page\DLT645_2007DebugPage.razor.cs" Link="Pages\DLT645\DLT645_2007DebugPage.razor.cs" />
|
||||
|
||||
<Content Include="..\..\Plugin\ThingsGateway.Plugin.DLT645\Page\DLT645_2007DebugPage.razor" Link="Pages\DLT645\DLT645_2007DebugPage.razor" />
|
||||
<Compile Include="..\..\Plugin\ThingsGateway.Plugin.DLT645\Page\DLT645_2007OverTcpDebugPage.razor.cs" Link="Pages\DLT645\DLT645_2007OverTcpDebugPage.razor.cs" />
|
||||
<Content Include="..\..\Plugin\ThingsGateway.Plugin.DLT645\Page\DLT645_2007OverTcpDebugPage.razor" Link="Pages\DLT645\DLT645_2007OverTcpDebugPage.razor" />
|
||||
|
||||
|
||||
|
||||
<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Modbus\Page\ModbusRtuDebugPage.razor.cs" Link="Pages\Modbus\ModbusRtuDebugPage.razor.cs" />
|
||||
<Content Include="..\..\Plugin\ThingsGateway.Plugin.Modbus\Page\ModbusRtuDebugPage.razor" Link="Pages\Modbus\ModbusRtuDebugPage.razor" />
|
||||
<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Modbus\Page\ModbusRtuOverTcpDebugPage.razor.cs" Link="Pages\Modbus\ModbusRtuOverTcpDebugPage.razor.cs" />
|
||||
@@ -133,20 +153,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<Content Update="wwwroot\**">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="..\..\Plugin\ThingsGateway.Plugin.Mqtt\Page\MqttClientDebugPage.razor" Link="Pages\Mqtt\MqttClientDebugPage.razor" />
|
||||
<Content Include="..\..\Plugin\ThingsGateway.Plugin.Mqtt\Page\MqttClientPage.razor" Link="Pages\Mqtt\MqttClientPage.razor" />
|
||||
<PackageReference Include="MQTTnet" Version="4.3.1.873" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#region copyright
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
@@ -10,12 +10,7 @@
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace ThingsGateway.Foundation.Serial;
|
||||
global using System;
|
||||
|
||||
/// <summary>
|
||||
/// 串口基接口
|
||||
/// </summary>
|
||||
public interface ISerial : ISocket
|
||||
{
|
||||
global using System.Windows.Forms;
|
||||
|
||||
}
|
||||
77
framework/Demo/ThingsGateway.Foundation.Demo.Winform/MainFrom.Designer.cs
generated
Normal file
@@ -0,0 +1,77 @@
|
||||
#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.Drawing;
|
||||
|
||||
namespace ThingsGateway.Foundation.Demo.Winform
|
||||
{
|
||||
partial class MainFrom
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainFrom));
|
||||
blazorWebView1 = new Microsoft.AspNetCore.Components.WebView.WindowsForms.BlazorWebView();
|
||||
SuspendLayout();
|
||||
//
|
||||
// blazorWebView1
|
||||
//
|
||||
blazorWebView1.Dock = DockStyle.Fill;
|
||||
blazorWebView1.Location = new Point(0, 0);
|
||||
blazorWebView1.Margin = new Padding(4);
|
||||
blazorWebView1.Name = "blazorWebView1";
|
||||
blazorWebView1.Size = new Size(1029, 529);
|
||||
blazorWebView1.TabIndex = 0;
|
||||
blazorWebView1.Text = "blazorWebView1";
|
||||
//
|
||||
// MainFrom
|
||||
//
|
||||
AutoScaleDimensions = new SizeF(9F, 20F);
|
||||
AutoScaleMode = AutoScaleMode.Font;
|
||||
ClientSize = new Size(1029, 529);
|
||||
Controls.Add(blazorWebView1);
|
||||
Icon = (Icon)resources.GetObject("$this.Icon");
|
||||
Margin = new Padding(4);
|
||||
Name = "MainFrom";
|
||||
Text = "Form1";
|
||||
FormClosed += MainFrom_FormClosed;
|
||||
ResumeLayout(false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private Microsoft.AspNetCore.Components.WebView.WindowsForms.BlazorWebView blazorWebView1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
#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 Microsoft.AspNetCore.Components.WebView.WindowsForms;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
using ThingsGateway.Components;
|
||||
|
||||
namespace ThingsGateway.Foundation.Demo.Winform
|
||||
{
|
||||
public partial class MainFrom : Form
|
||||
{
|
||||
public MainFrom()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
var services = new ServiceCollection();
|
||||
services.AddWindowsFormsBlazorWebView();
|
||||
services.ThingsGatewayComponentsConfigureServices();
|
||||
|
||||
blazorWebView1.HostPage = "wwwroot/index.html";
|
||||
blazorWebView1.Services = services.BuildServiceProvider();
|
||||
this.Text = "ThingsGateway.Foundation.Demo";
|
||||
blazorWebView1.RootComponents.Add<ThingsGateway.Foundation.Demo.App>("#app");
|
||||
}
|
||||
|
||||
private void MainFrom_FormClosed(object sender, FormClosedEventArgs e)
|
||||
{
|
||||
Application.Exit();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,197 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
|
||||
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
AAABAAEAICAAAAEAIACoEAAAFgAAACgAAAAgAAAAQAAAAAEAIAAAAAAAABAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAwo82AMKPNgvCjzYkwo82JsKPNifCjzYqwo82IcKPNgLCjzYAAAAAAAAA
|
||||
AAAAAAAAAAAAAMKPNgDCjzYBwo82HsKPNknCjzZewo82QcKPNhLCjzYAwo82AAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADCjzYAwo82S8KPNtPCjzbiwo8258KPNuDCjzatwo82EsKP
|
||||
NgAAAAAAAAAAAAAAAADCjzYAwo82BsKPNmvCjzbbwo826MKPNtvCjzbhwo82vcKPNmDCjzYywo82AAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMKPNgDCjzYPwo82O8KPNs7Cjzb/wo82iMKP
|
||||
Nh7CjzYCwo82AAAAAAAAAAAAwo82AMKPNgDCjzZnwo8298KPNsLCjzY6wo82GsKPNjTCjzbJwo82/8KP
|
||||
NpTCjzYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMKPNgDCjzYIwo82vsKP
|
||||
Nv/CjzZowo82AAAAAAAAAAAAAAAAAAAAAADCjzYAwo82JMKPNtnCjzbxwo82QcKPNgDCjzYAwo82AMKP
|
||||
NpHCjzb/wo82lsKPNgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwo82AMKP
|
||||
NgjCjza9wo82/8KPNmjCjzYAAAAAAAAAAAAAAAAAwo82AMKPNgDCjzZ2wo82/8KPNrnCjzYKwo82AAAA
|
||||
AADCjzYAwo82jcKPNv/CjzaWwo82AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AADCjzYAwo82CMKPNr3Cjzb/wo82aMKPNgAAAAAAAAAAAAAAAADCjzYAwo82CcKPNrrCjzb/wo82fcKP
|
||||
NgDCjzYAAAAAAMKPNgDCjzaLwo82/8KPNpbCjzYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAMKPNgDCjzYIwo82vMKPNv/CjzZpwo82AAAAAAAAAAAAAAAAAMKPNgDCjzYfwo8238KP
|
||||
Nv3CjzZRwo82AMKPNgDCjzYBwo82B8KPNpnCjzb/wo82psKPNgrCjzYAwo82AAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAwo82AMKPNgjCjza8wo82/8KPNmnCjzYAAAAAAAAAAAAAAAAAwo82AMKP
|
||||
NjbCjzbxwo829sKPNj7CjzYAwo82AMKPNiPCjzaywo827cKPNv/Cjzbywo82qMKPNhPCjzYAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADCjzYAwo82CMKPNrvCjzb/wo82acKPNgAAAAAAAAAAAAAA
|
||||
AADCjzYAwo82P8KPNvfCjzbzwo82OcKPNgDCjzYAwo82D8KPNlnCjzZiwo82X8KPNmDCjzZRwo82CcKP
|
||||
NgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMKPNgDCjzYHwo82usKPNv/CjzZpwo82AAAA
|
||||
AAAAAAAAAAAAAMKPNgDCjzY+wo829sKPNvTCjzY8wo82AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwo82AMKPNgfCjza6wo82/8KP
|
||||
NmnCjzYAAAAAAAAAAAAAAAAAwo82AMKPNirCjzbpwo82+MKPNkDCjzYAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADCjzYAwo82B8KP
|
||||
NrnCjzb/wo82acKPNgAAAAAAAAAAAAAAAADCjzYAwo82FcKPNtLCjzb/wo82VsKPNgAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwo82AMKPNgLCjzYTwo82BMKP
|
||||
NgDCjzYHwo82t8KPNv/CjzZpwo82AMKPNgDCjzYMwo82E8KPNgDCjzYCwo82n8KPNv/CjzaEwo82AMKP
|
||||
NgAAAAAAwo82AMKPNgDCjzZPwo82XcKPNgLCjzYAAAAAAAAAAAAAAAAAAAAAAAAAAADCjzYAwo82F8KP
|
||||
NrTCjzY6wo82AMKPNgbCjza0wo82/8KPNmnCjzYAwo82AMKPNnPCjzaawo82A8KPNgDCjzZOwo82+MKP
|
||||
NsbCjzYRwo82AAAAAADCjzYAwo82DcKPNsLCjzagwo82AMKPNgAAAAAAAAAAAAAAAAAAAAAAAAAAAMKP
|
||||
NgDCjzYPwo82ysKPNpPCjzYBwo82BcKPNrHCjzb/wo82acKPNgDCjzYUwo82zMKPNpPCjzYAwo82AMKP
|
||||
NgrCjzanwo82/MKPNmnCjzYAwo82AMKPNgDCjzZRwo8298KPNnbCjzYAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAwo82AMKPNgDCjzaawo827cKPNmHCjzYswo82vMKPNv/CjzaEwo82K8KPNoDCjzb5wo82ZMKP
|
||||
NgAAAAAAwo82AMKPNi7CjzbWwo825sKPNlnCjzYdwo82SMKPNtTCjzb9wo82UsKPNgAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAwo82AMKPNmHCjzb3wo828cKPNt/Cjzbuwo8298KPNurCjzbjwo829MKP
|
||||
NurCjzY6wo82AAAAAADCjzYAwo82AMKPNjfCjza8wo826cKPNtvCjzbewo82ycKPNs7CjzYvwo82AAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADCjzYAwo82EsKPNj3CjzZAwo82QcKPNkDCjzY/wo82QMKP
|
||||
NkDCjzY/wo82OMKPNgrCjzYAAAAAAAAAAADCjzYAwo82AMKPNg/CjzY5wo82SsKPNjDCjzYOwo82G8KP
|
||||
NgXCjzYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAA//////////////////////////////////////wH4H/8B8Af/AfAH/4f
|
||||
hx/+H4cf/h8PH/4fDAf+HwwH/h8MB/4fD//+Hw///h8P/+IZD4/iGIcP4BGHH+ABwB/wAeAf8AHwH///
|
||||
//////////////////////////////////8=
|
||||
</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -0,0 +1,29 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace ThingsGateway.Foundation.Demo.Winform
|
||||
{
|
||||
internal static class Program
|
||||
{
|
||||
/// <summary>
|
||||
/// The main entry point for the application.
|
||||
/// </summary>
|
||||
[STAThread]
|
||||
static void Main()
|
||||
{
|
||||
// To customize application configuration such as set high DPI settings or default font,
|
||||
// see https://aka.ms/applicationconfiguration.
|
||||
ApplicationConfiguration.Initialize();
|
||||
Application.Run(new MainFrom());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Razor">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<ApplicationIcon>favicon.ico</ApplicationIcon>
|
||||
<TargetFrameworks>net7.0-windows</TargetFrameworks>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="favicon.ico" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="favicon.ico">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebView.WindowsForms" Version="7.0.96" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\ThingsGateway.Foundation.Demo.Rcl\ThingsGateway.Foundation.Demo.Rcl.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<Content Update="wwwroot\favicon.ico">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\favicon.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\index.html">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
|
||||
</Project>
|
||||
BIN
framework/Demo/ThingsGateway.Foundation.Demo.Winform/favicon.ico
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 10 KiB |
@@ -0,0 +1,41 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover" />
|
||||
<title>ThingsGateway.Foundation.Demo</title>
|
||||
<base href="/" />
|
||||
|
||||
<link rel="icon" href="favicon.ico" type="image/x-icon">
|
||||
|
||||
|
||||
<link href="_content/Masa.Blazor/css/masa-blazor.min.css" rel="stylesheet" />
|
||||
<link href="_content/ThingsGateway.Components/css/materialdesign/v7.1.96/css/materialdesignicons.min.css" rel="stylesheet">
|
||||
<link href="_content/ThingsGateway.Components/css/material/icons.css" rel="stylesheet">
|
||||
<link href="_content/ThingsGateway.Components/css/fontawesome/v6.4.0/css/all.min.css" rel="stylesheet">
|
||||
<link href="_content/ThingsGateway.Components/style/custom.css" rel="stylesheet">
|
||||
<link href="_content/ThingsGateway.Components/prism/prism-material-dark-for-masa.css" rel="stylesheet">
|
||||
<link href="_content/ThingsGateway.Components/prism/prism-line-highlight.min.css" rel="stylesheet">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
||||
<div id="blazor-error-ui">
|
||||
<span>
|
||||
<environment include="Staging,Production">
|
||||
An error has occurred. This application may no longer respond until reloaded.
|
||||
</environment>
|
||||
<environment include="Development">
|
||||
An unhandled exception has occurred. See browser dev tools for details.
|
||||
</environment>
|
||||
</span>
|
||||
<a href="" class="reload">Reload</a>
|
||||
<a class="dismiss">🗙</a>
|
||||
</div>
|
||||
|
||||
<script src="_framework/blazor.webview.js" autostart="true"></script>
|
||||
<script src="_content/ThingsGateway.Components/prism/prism.min.js"></script>
|
||||
<script src="_content/BlazorComponent/js/blazor-component.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,6 +1,6 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<Version>3.0.0.24</Version>
|
||||
<Version>3.0.1.0</Version>
|
||||
<GenerateDocumentationFile>True</GenerateDocumentationFile>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<TargetFrameworks>net45;netstandard2.0;net6.0;net7.0</TargetFrameworks>
|
||||
|
||||
@@ -35,12 +35,7 @@ public class DataInfo
|
||||
}
|
||||
internal static class DLT645Helper
|
||||
{
|
||||
internal static byte[] BytesAdd(this byte[] bytes, int value)
|
||||
{
|
||||
for (int index = 0; index < bytes.Length; ++index)
|
||||
bytes[index] = (byte)(bytes[index] + value);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
|
||||
internal static string Get2007ErrorMessage(byte buffer)
|
||||
{
|
||||
|
||||
@@ -47,7 +47,7 @@ public class OPCUAClient : IDisposable
|
||||
/// <summary>
|
||||
/// 当前保存的变量名称列表
|
||||
/// </summary>
|
||||
public List<string> Variables = new();
|
||||
public List<List<string>> Variables = new();
|
||||
|
||||
/// <summary>
|
||||
/// 当前的变量名称/OPC变量节点
|
||||
@@ -516,9 +516,9 @@ public class OPCUAClient : IDisposable
|
||||
/// <summary>
|
||||
/// 连接到服务器
|
||||
/// </summary>
|
||||
public async Task ConnectAsync()
|
||||
public async Task ConnectAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
await ConnectAsync(OPCNode.OPCUrl);
|
||||
await ConnectAsync(OPCNode.OPCUrl, cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -538,7 +538,7 @@ public class OPCUAClient : IDisposable
|
||||
/// Creates a new session.
|
||||
/// </summary>
|
||||
/// <returns>The new session object.</returns>
|
||||
private async Task<ISession> ConnectAsync(string serverUrl)
|
||||
private async Task<ISession> ConnectAsync(string serverUrl, CancellationToken cancellationToken)
|
||||
{
|
||||
PrivateDisconnect();
|
||||
|
||||
@@ -547,6 +547,7 @@ public class OPCUAClient : IDisposable
|
||||
throw new ArgumentNullException("未初始化配置");
|
||||
}
|
||||
var useSecurity = OPCNode?.IsUseSecurity ?? true;
|
||||
|
||||
EndpointDescription endpointDescription = CoreClientUtils.SelectEndpoint(m_configuration, serverUrl, useSecurity, 10000);
|
||||
EndpointConfiguration endpointConfiguration = EndpointConfiguration.Create(m_configuration);
|
||||
ConfiguredEndpoint endpoint = new(null, endpointDescription, endpointConfiguration);
|
||||
@@ -569,7 +570,8 @@ public class OPCUAClient : IDisposable
|
||||
(string.IsNullOrEmpty(OPCUAName)) ? m_configuration.ApplicationName : OPCUAName,
|
||||
60000,
|
||||
userIdentity,
|
||||
Array.Empty<string>());
|
||||
Array.Empty<string>(), cancellationToken
|
||||
).ConfigureAwait(false);
|
||||
typeSystem = new ComplexTypeSystem(m_session);
|
||||
|
||||
m_session.KeepAliveInterval = OPCNode.KeepAliveInterval == 0 ? 60000 : OPCNode.KeepAliveInterval;
|
||||
@@ -582,7 +584,12 @@ public class OPCUAClient : IDisposable
|
||||
|
||||
//如果是订阅模式,连接时添加订阅组
|
||||
if (OPCNode.ActiveSubscribe)
|
||||
await AddSubscriptionAsync(Guid.NewGuid().ToString(), Variables.ToArray(), OPCNode.LoadType);
|
||||
{
|
||||
foreach (var item in Variables)
|
||||
{
|
||||
await AddSubscriptionAsync(Guid.NewGuid().ToString(), item.ToArray(), OPCNode.LoadType);
|
||||
}
|
||||
}
|
||||
return m_session;
|
||||
}
|
||||
|
||||
@@ -739,7 +746,7 @@ public class OPCUAClient : IDisposable
|
||||
NodeId nodeToRead = new(nodeIdStr);
|
||||
var node = (VariableNode)await m_session.ReadNodeAsync(nodeToRead, NodeClass.Variable, false, cancellationToken);
|
||||
if (OPCNode.LoadType)
|
||||
await typeSystem.LoadType(node.DataType);
|
||||
await typeSystem.LoadType(node.DataType).ConfigureAwait(false);
|
||||
_variableDicts.AddOrUpdate(nodeIdStr, node);
|
||||
return node;
|
||||
}
|
||||
@@ -779,7 +786,7 @@ public class OPCUAClient : IDisposable
|
||||
if (StatusCode.IsGood(nodes.Item2[i].StatusCode))
|
||||
{
|
||||
var node = ((VariableNode)nodes.Item1[i]);
|
||||
await typeSystem.LoadType(node.DataType);
|
||||
await typeSystem.LoadType(node.DataType).ConfigureAwait(false);
|
||||
_variableDicts.AddOrUpdate(nodeIdStrs[i], node);
|
||||
}
|
||||
else
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="OPCFoundation.NetStandard.Opc.Ua.Client" Version="1.4.372.56" />
|
||||
<PackageReference Include="OPCFoundation.NetStandard.Opc.Ua.Client.ComplexTypes" Version="1.4.372.56" />
|
||||
<PackageReference Include="OPCFoundation.NetStandard.Opc.Ua.Client" Version="1.4.372.76" />
|
||||
<PackageReference Include="OPCFoundation.NetStandard.Opc.Ua.Client.ComplexTypes" Version="1.4.372.76" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -36,11 +36,42 @@ internal partial class SiemensHelper
|
||||
// return OperResult.CreateSuccessResult<byte[]>(numArray);
|
||||
//}
|
||||
|
||||
internal static OperResult<byte[]> AnalysisReadByte(byte[] sends, byte[] content)
|
||||
internal static OperResult<byte[], FilterResult> AnalysisReadByte(byte[] sends, byte[] content)
|
||||
{
|
||||
int length = 0;
|
||||
int itemLen = (sends.Length - 19) / 12;
|
||||
|
||||
//添加错误代码校验
|
||||
if (content[17] + content[18] > 0)
|
||||
{
|
||||
return new($"PLC返回错误,错误类型{content[17].ToString("X2")}错误代码:{content[18].ToString("X2")}")
|
||||
{
|
||||
Content2 = FilterResult.Success
|
||||
};
|
||||
}
|
||||
if (content.Length < 21)
|
||||
{
|
||||
return new($"长度不足")
|
||||
{
|
||||
Content2 = FilterResult.Cache
|
||||
};
|
||||
}
|
||||
if (content.Length < 25 + content[20])
|
||||
{
|
||||
return new($"长度不足")
|
||||
{
|
||||
Content2 = FilterResult.Cache
|
||||
};
|
||||
}
|
||||
//添加返回代码校验
|
||||
if (content[21] != 0xff)
|
||||
{
|
||||
return new($"PLC返回错误,返回代码{content[21].ToString("X2")}")
|
||||
{
|
||||
Content2 = FilterResult.Success
|
||||
};
|
||||
}
|
||||
|
||||
for (int index = 0; index < itemLen; index++)
|
||||
{
|
||||
if (sends[22 + (index * 12)] >= (byte)S7WordLength.Word)
|
||||
@@ -53,9 +84,9 @@ internal partial class SiemensHelper
|
||||
}
|
||||
}
|
||||
|
||||
if (content.Length < 21 || content[20] != itemLen)
|
||||
if (content[20] != itemLen)
|
||||
{
|
||||
return new OperResult<byte[]>("数据块长度校验失败");
|
||||
return new("数据块长度校验失败");
|
||||
}
|
||||
|
||||
byte[] dataArray = new byte[length];
|
||||
@@ -105,29 +136,39 @@ internal partial class SiemensHelper
|
||||
}
|
||||
else
|
||||
{
|
||||
return new OperResult<byte[]>((int)content[index2] + GetCpuError(content[index2]));
|
||||
return new((int)content[index2] + GetCpuError(content[index2]))
|
||||
{
|
||||
Content2 = FilterResult.Success
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
return OperResult.CreateSuccessResult(dataArray);
|
||||
return OperResult.CreateSuccessResult(dataArray, FilterResult.Success);
|
||||
|
||||
}
|
||||
|
||||
internal static OperResult<byte[]> AnalysisWrite(byte[] content)
|
||||
internal static OperResult<byte[], FilterResult> AnalysisWrite(byte[] content)
|
||||
{
|
||||
if (content.Length < 22)
|
||||
{
|
||||
return new OperResult<byte[]>() { Message = "未知错误" };
|
||||
return new()
|
||||
{
|
||||
Message = "长度不足",
|
||||
Content2 = FilterResult.Success
|
||||
};
|
||||
}
|
||||
|
||||
byte err = content[21];
|
||||
if (err != byte.MaxValue)
|
||||
{
|
||||
return new OperResult<byte[]>((int)content[21] + GetCpuError(content[21]));
|
||||
return new($"错误代码:{(int)content[21]}描述:{GetCpuError(content[21])}")
|
||||
{
|
||||
Content2 = FilterResult.Success
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
return OperResult.CreateSuccessResult(content);
|
||||
return OperResult.CreateSuccessResult(content, FilterResult.Success);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -35,10 +35,10 @@ public class SiemensS7PLCDataHandleAdapter : ReadWriteDevicesTcpDataHandleAdapte
|
||||
/// <inheritdoc/>
|
||||
protected override FilterResult UnpackResponse(SiemensMessage request, byte[] send, byte[] body, byte[] response)
|
||||
{
|
||||
var result = new OperResult<byte[]>();
|
||||
var result = new OperResult<byte[], FilterResult>();
|
||||
if (response[2] * 256 + response[3] == 7)
|
||||
{
|
||||
result = new OperResult<byte[]>() { Content = response };
|
||||
result = new() { Content = response, Content2 = FilterResult.Success };
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -56,6 +56,6 @@ public class SiemensS7PLCDataHandleAdapter : ReadWriteDevicesTcpDataHandleAdapte
|
||||
request.ErrorCode = result.ErrorCode;
|
||||
request.Message = result.Message;
|
||||
request.Content = result.Content;
|
||||
return FilterResult.Success;
|
||||
return result.Content2;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
0x00 Reserved 未定义,预留
|
||||
|
||||
0x01 Hardware error 硬件错误
|
||||
|
||||
0x03 Accessing the object not allowed 对象不允许访问
|
||||
|
||||
0x05 Invalid address 无效地址,所需的地址超出此PLC的极限
|
||||
|
||||
0x06 Data type not supported 数据类型不支持
|
||||
|
||||
0x07 Data type inconsistent 日期类型不一致
|
||||
|
||||
0x0a Object does not exist 对象不存在
|
||||
|
||||
0xff Success 成功
|
||||
@@ -0,0 +1,825 @@
|
||||
附录一:错误码具体含义
|
||||
|
||||
0x0000
|
||||
|
||||
没有错误
|
||||
|
||||
0x0110
|
||||
|
||||
块号无效
|
||||
|
||||
0x0111
|
||||
|
||||
请求长度无效
|
||||
|
||||
0x0112
|
||||
|
||||
参数无效
|
||||
|
||||
0x0113
|
||||
|
||||
块类型无效
|
||||
|
||||
0x0114
|
||||
|
||||
找不到块
|
||||
|
||||
0x0115
|
||||
|
||||
块已存在
|
||||
|
||||
0x0116
|
||||
|
||||
块被写保护
|
||||
|
||||
0x0117
|
||||
|
||||
块/操作系统更新太大
|
||||
|
||||
0x0118
|
||||
|
||||
块号无效
|
||||
|
||||
0x0119
|
||||
|
||||
输入的密码不正确
|
||||
|
||||
0x011A
|
||||
|
||||
PG资源错误
|
||||
|
||||
0x011B
|
||||
|
||||
PLC资源错误
|
||||
|
||||
0x011C
|
||||
|
||||
协议错误
|
||||
|
||||
0x011D
|
||||
|
||||
块太多(与模块相关的限制)
|
||||
|
||||
0x011E
|
||||
|
||||
不再与数据库建立连接,或者S7DOS句柄无效
|
||||
|
||||
0x011F
|
||||
|
||||
结果缓冲区太小
|
||||
|
||||
0x0120
|
||||
|
||||
块结束列表
|
||||
|
||||
0x0140
|
||||
|
||||
可用内存不足
|
||||
|
||||
0x0141
|
||||
|
||||
由于缺少资源,无法处理作业
|
||||
|
||||
0x8001
|
||||
|
||||
当块处于当前状态时,无法执行请求的服务
|
||||
|
||||
0x8003
|
||||
|
||||
S7协议错误:传输块时发生错误
|
||||
|
||||
0x8100
|
||||
|
||||
应用程序,一般错误:远程模块未知的服务
|
||||
|
||||
0x8104
|
||||
|
||||
未在模块上实现此服务或报告了帧错误
|
||||
|
||||
0x8204
|
||||
|
||||
对象的类型规范不一致
|
||||
|
||||
0x8205
|
||||
|
||||
复制的块已存在且未链接
|
||||
|
||||
0x8301
|
||||
|
||||
模块上的内存空间或工作内存不足,或者指定的存储介质不可访问
|
||||
|
||||
0x8302
|
||||
|
||||
可用资源太少或处理器资源不可用
|
||||
|
||||
0x8304
|
||||
|
||||
无法进一步并行上传。存在资源瓶颈
|
||||
|
||||
0x8305
|
||||
|
||||
功能不可用
|
||||
|
||||
0x8306
|
||||
|
||||
工作内存不足(用于复制,链接,加载AWP)
|
||||
|
||||
0x8307
|
||||
|
||||
保持性工作记忆不够(用于复制,链接,加载AWP)
|
||||
|
||||
0x8401
|
||||
|
||||
S7协议错误:无效的服务序列(例如,加载或上载块)
|
||||
|
||||
0x8402
|
||||
|
||||
由于寻址对象的状态,服务无法执行
|
||||
|
||||
0x8404
|
||||
|
||||
S7协议:无法执行该功能
|
||||
|
||||
0x8405
|
||||
|
||||
远程块处于DISABLE状态(CFB)。该功能无法执行
|
||||
|
||||
0x8500
|
||||
|
||||
S7协议错误:帧错误
|
||||
|
||||
0x8503
|
||||
|
||||
来自模块的警报:服务过早取消
|
||||
|
||||
0x8701
|
||||
|
||||
寻址通信伙伴上的对象时出错(例如,区域长度错误)
|
||||
|
||||
0x8702
|
||||
|
||||
模块不支持所请求的服务
|
||||
|
||||
0x8703
|
||||
|
||||
拒绝访问对象
|
||||
|
||||
0x8704
|
||||
|
||||
访问错误:对象已损坏
|
||||
|
||||
0xD001
|
||||
|
||||
协议错误:非法的作业号
|
||||
|
||||
0xD002
|
||||
|
||||
参数错误:非法的作业变体
|
||||
|
||||
0xD003
|
||||
|
||||
参数错误:模块不支持调试功能
|
||||
|
||||
0xD004
|
||||
|
||||
参数错误:作业状态非法
|
||||
|
||||
0xD005
|
||||
|
||||
参数错误:作业终止非法
|
||||
|
||||
0xD006
|
||||
|
||||
参数错误:非法链路断开ID
|
||||
|
||||
0xD007
|
||||
|
||||
参数错误:缓冲区元素数量非法
|
||||
|
||||
0xD008
|
||||
|
||||
参数错误:扫描速率非法
|
||||
|
||||
0xD009
|
||||
|
||||
参数错误:执行次数非法
|
||||
|
||||
0xD00A
|
||||
|
||||
参数错误:非法触发事件
|
||||
|
||||
0xD00B
|
||||
|
||||
参数错误:非法触发条件
|
||||
|
||||
0xD011
|
||||
|
||||
调用环境路径中的参数错误:块不存在
|
||||
|
||||
0xD012
|
||||
|
||||
参数错误:块中的地址错误
|
||||
|
||||
0xD014
|
||||
|
||||
参数错误:正在删除/覆盖块
|
||||
|
||||
0xD015
|
||||
|
||||
参数错误:标签地址非法
|
||||
|
||||
0xD016
|
||||
|
||||
参数错误:由于用户程序错误,无法测试作业
|
||||
|
||||
0xD017
|
||||
|
||||
参数错误:非法触发号
|
||||
|
||||
0xD025
|
||||
|
||||
参数错误:路径无效
|
||||
|
||||
0xD026
|
||||
|
||||
参数错误:非法访问类型
|
||||
|
||||
0xD027
|
||||
|
||||
参数错误:不允许此数据块数
|
||||
|
||||
0xD031
|
||||
|
||||
内部协议错误
|
||||
|
||||
0xD032
|
||||
|
||||
参数错误:结果缓冲区长度错误
|
||||
|
||||
0xD033
|
||||
|
||||
协议错误:作业长度错误
|
||||
|
||||
0xD03F
|
||||
|
||||
编码错误:参数部分出错(例如,保留字节不等于0)
|
||||
|
||||
0xD041
|
||||
|
||||
数据错误:非法状态列表ID
|
||||
|
||||
0xD042
|
||||
|
||||
数据错误:标签地址非法
|
||||
|
||||
0xD043
|
||||
|
||||
数据错误:找不到引用的作业,检查作业数据
|
||||
|
||||
0xD044
|
||||
|
||||
数据错误:标签值非法,检查作业数据
|
||||
|
||||
0xD045
|
||||
|
||||
数据错误:HOLD中不允许退出ODIS控制
|
||||
|
||||
0xD046
|
||||
|
||||
数据错误:运行时测量期间非法测量阶段
|
||||
|
||||
0xD047
|
||||
|
||||
数据错误:“读取作业列表”中的非法层次结构
|
||||
|
||||
0xD048
|
||||
|
||||
数据错误:“删除作业”中的非法删除ID
|
||||
|
||||
0xD049
|
||||
|
||||
“替换作业”中的替换ID无效
|
||||
|
||||
0xD04A
|
||||
|
||||
执行'程序状态'时出错
|
||||
|
||||
0xD05F
|
||||
|
||||
编码错误:数据部分出错(例如,保留字节不等于0,...)
|
||||
|
||||
0xD061
|
||||
|
||||
资源错误:没有作业的内存空间
|
||||
|
||||
0xD062
|
||||
|
||||
资源错误:作业列表已满
|
||||
|
||||
0xD063
|
||||
|
||||
资源错误:触发事件占用
|
||||
|
||||
0xD064
|
||||
|
||||
资源错误:没有足够的内存空间用于一个结果缓冲区元素
|
||||
|
||||
0xD065
|
||||
|
||||
资源错误:没有足够的内存空间用于多个结果缓冲区元素
|
||||
|
||||
0xD066
|
||||
|
||||
资源错误:可用于运行时测量的计时器被另一个作业占用
|
||||
|
||||
0xD067
|
||||
|
||||
资源错误:“修改标记”作业过多(特别是多处理器操作)
|
||||
|
||||
0xD081
|
||||
|
||||
当前模式下不允许使用的功能
|
||||
|
||||
0xD082
|
||||
|
||||
模式错误:无法退出HOLD模式
|
||||
|
||||
0xD0A1
|
||||
|
||||
当前保护级别不允许使用的功能
|
||||
|
||||
0xD0A2
|
||||
|
||||
目前无法运行,因为正在运行的函数会修改内存
|
||||
|
||||
0xD0A3
|
||||
|
||||
I / O上活动的“修改标记”作业太多(特别是多处理器操作)
|
||||
|
||||
0xD0A4
|
||||
|
||||
'强制'已经建立
|
||||
|
||||
0xD0A5
|
||||
|
||||
找不到引用的作业
|
||||
|
||||
0xD0A6
|
||||
|
||||
无法禁用/启用作业
|
||||
|
||||
0xD0A7
|
||||
|
||||
无法删除作业,例如因为当前正在读取作业
|
||||
|
||||
0xD0A8
|
||||
|
||||
无法替换作业,例如因为当前正在读取或删除作业
|
||||
|
||||
0xD0A9
|
||||
|
||||
无法读取作业,例如因为当前正在删除作业
|
||||
|
||||
0xD0AA
|
||||
|
||||
处理操作超出时间限制
|
||||
|
||||
0xD0AB
|
||||
|
||||
进程操作中的作业参数无效
|
||||
|
||||
0xD0AC
|
||||
|
||||
进程操作中的作业数据无效
|
||||
|
||||
0xD0AD
|
||||
|
||||
已设置操作模式
|
||||
|
||||
0xD0AE
|
||||
|
||||
作业是通过不同的连接设置的,只能通过此连接进行处理
|
||||
|
||||
0xD0C1
|
||||
|
||||
访问标签时至少检测到一个错误
|
||||
|
||||
0xD0C2
|
||||
|
||||
切换到STOP / HOLD模式
|
||||
|
||||
0xD0C3
|
||||
|
||||
访问标记时至少检测到一个错误。模式更改为STOP / HOLD
|
||||
|
||||
0xD0C4
|
||||
|
||||
运行时测量期间超时
|
||||
|
||||
0xD0C5
|
||||
|
||||
块堆栈的显示不一致,因为块被删除/重新加载
|
||||
|
||||
0xD0C6
|
||||
|
||||
作业已被删除,因为它所引用的作业已被删除
|
||||
|
||||
0xD0C7
|
||||
|
||||
由于退出了STOP模式,因此作业被自动删除
|
||||
|
||||
0xD0C8
|
||||
|
||||
由于测试作业和正在运行的程序之间不一致,“块状态”中止
|
||||
|
||||
0xD0C9
|
||||
|
||||
通过复位OB90退出状态区域
|
||||
|
||||
0xD0CA
|
||||
|
||||
通过在退出前重置OB90并访问错误读取标签退出状态范围
|
||||
|
||||
0xD0CB
|
||||
|
||||
外设输出的输出禁用再次激活
|
||||
|
||||
0xD0CC
|
||||
|
||||
调试功能的数据量受时间限制
|
||||
|
||||
0xD201
|
||||
|
||||
块名称中的语法错误
|
||||
|
||||
0xD202
|
||||
|
||||
函数参数中的语法错误
|
||||
|
||||
0xD205
|
||||
|
||||
RAM中已存在链接块:无法进行条件复制
|
||||
|
||||
0xD206
|
||||
|
||||
EPROM中已存在链接块:无法进行条件复制
|
||||
|
||||
0xD208
|
||||
|
||||
超出模块的最大复制(未链接)块数
|
||||
|
||||
0xD209
|
||||
|
||||
(至少)模块上找不到给定块之一
|
||||
|
||||
0xD20A
|
||||
|
||||
超出了可以与一个作业链接的最大块数
|
||||
|
||||
0xD20B
|
||||
|
||||
超出了一个作业可以删除的最大块数
|
||||
|
||||
0xD20C
|
||||
|
||||
OB无法复制,因为关联的优先级不存在
|
||||
|
||||
0xD20D
|
||||
|
||||
SDB无法解释(例如,未知数)
|
||||
|
||||
0xD20E
|
||||
|
||||
没有(进一步)阻止可用
|
||||
|
||||
0xD20F
|
||||
|
||||
超出模块特定的最大块大小
|
||||
|
||||
0xD210
|
||||
|
||||
块号无效
|
||||
|
||||
0xD212
|
||||
|
||||
标头属性不正确(与运行时相关)
|
||||
|
||||
0xD213
|
||||
|
||||
SDB太多。请注意对正在使用的模块的限制
|
||||
|
||||
0xD216
|
||||
|
||||
无效的用户程序 - 重置模块
|
||||
|
||||
0xD217
|
||||
|
||||
不允许在模块属性中指定的保护级别
|
||||
|
||||
0xD218
|
||||
|
||||
属性不正确(主动/被动)
|
||||
|
||||
0xD219
|
||||
|
||||
块长度不正确(例如,第一部分或整个块的长度不正确)
|
||||
|
||||
0xD21A
|
||||
|
||||
本地数据长度不正确或写保护错误
|
||||
|
||||
0xD21B
|
||||
|
||||
模块无法压缩或压缩早期中断
|
||||
|
||||
0xD21D
|
||||
|
||||
传输的动态项目数据量是非法的
|
||||
|
||||
0xD21E
|
||||
|
||||
无法为模块(例如FM,CP)分配参数。系统数据无法链接
|
||||
|
||||
0xD220
|
||||
|
||||
编程语言无效。请注意对正在使用的模块的限制
|
||||
|
||||
0xD221
|
||||
|
||||
连接或路由的系统数据无效
|
||||
|
||||
0xD222
|
||||
|
||||
全局数据定义的系统数据包含无效参数
|
||||
|
||||
0xD223
|
||||
|
||||
通信功能块的实例数据块错误或超出最大背景数据块数
|
||||
|
||||
0xD224
|
||||
|
||||
SCAN系统数据块包含无效参数
|
||||
|
||||
0xD225
|
||||
|
||||
DP系统数据块包含无效参数
|
||||
|
||||
0xD226
|
||||
|
||||
块中发生结构错误
|
||||
|
||||
0xD230
|
||||
|
||||
块中发生结构错误
|
||||
|
||||
0xD231
|
||||
|
||||
至少有一个已加载的OB无法复制,因为关联的优先级不存在
|
||||
|
||||
0xD232
|
||||
|
||||
加载块的至少一个块编号是非法的
|
||||
|
||||
0xD234
|
||||
|
||||
块在指定的内存介质或作业中存在两次
|
||||
|
||||
0xD235
|
||||
|
||||
该块包含不正确的校验和
|
||||
|
||||
0xD236
|
||||
|
||||
该块不包含校验和
|
||||
|
||||
0xD237
|
||||
|
||||
您将要加载块两次,即CPU上已存在具有相同时间戳的块
|
||||
|
||||
0xD238
|
||||
|
||||
指定的块中至少有一个不是DB
|
||||
|
||||
0xD239
|
||||
|
||||
至少有一个指定的DB在装载存储器中不可用作链接变量
|
||||
|
||||
0xD23A
|
||||
|
||||
至少有一个指定的DB与复制和链接的变体有很大不同
|
||||
|
||||
0xD240
|
||||
|
||||
违反了协调规则
|
||||
|
||||
0xD241
|
||||
|
||||
当前保护级别不允许该功能
|
||||
|
||||
0xD242
|
||||
|
||||
处理F块时的保护冲突
|
||||
|
||||
0xD250
|
||||
|
||||
更新和模块ID或版本不匹配
|
||||
|
||||
0xD251
|
||||
|
||||
操作系统组件序列不正确
|
||||
|
||||
0xD252
|
||||
|
||||
校验和错误
|
||||
|
||||
0xD253
|
||||
|
||||
没有可用的可执行加载程序; 只能使用存储卡进行更新
|
||||
|
||||
0xD254
|
||||
|
||||
操作系统中的存储错误
|
||||
|
||||
0xD280
|
||||
|
||||
在S7-300 CPU中编译块时出错
|
||||
|
||||
0xD2A1
|
||||
|
||||
块上的另一个块功能或触发器处于活动状态
|
||||
|
||||
0xD2A2
|
||||
|
||||
块上的触发器处于活动状态。首先完成调试功能
|
||||
|
||||
0xD2A3
|
||||
|
||||
块未激活(链接),块被占用或块当前被标记为删除
|
||||
|
||||
0xD2A4
|
||||
|
||||
该块已被另一个块函数处理
|
||||
|
||||
0xD2A6
|
||||
|
||||
无法同时保存和更改用户程序
|
||||
|
||||
0xD2A7
|
||||
|
||||
块具有“未链接”属性或未处理
|
||||
|
||||
0xD2A8
|
||||
|
||||
激活的调试功能阻止将参数分配给CPU
|
||||
|
||||
0xD2A9
|
||||
|
||||
正在为CPU分配新参数
|
||||
|
||||
0xD2AA
|
||||
|
||||
当前正在为模块分配新参数
|
||||
|
||||
0xD2AB
|
||||
|
||||
当前正在更改动态配置限制
|
||||
|
||||
0xD2AC
|
||||
|
||||
正在运行的激活或取消激活分配(SFC 12)暂时阻止R-KiR过程
|
||||
|
||||
0xD2B0
|
||||
|
||||
在RUN(CiR)中配置时发生错误
|
||||
|
||||
0xD2C0
|
||||
|
||||
已超出最大工艺对象数
|
||||
|
||||
0xD2C1
|
||||
|
||||
模块上已存在相同的技术数据块
|
||||
|
||||
0xD2C2
|
||||
|
||||
无法下载用户程序或下载硬件配置
|
||||
|
||||
0xD401
|
||||
|
||||
信息功能不可用
|
||||
|
||||
0xD402
|
||||
|
||||
信息功能不可用
|
||||
|
||||
0xD403
|
||||
|
||||
服务已登录/注销(诊断/ PMC)
|
||||
|
||||
0xD404
|
||||
|
||||
达到的最大节点数。不再需要登录诊断/ PMC
|
||||
|
||||
0xD405
|
||||
|
||||
不支持服务或函数参数中的语法错误
|
||||
|
||||
0xD406
|
||||
|
||||
当前不可用的必需信息
|
||||
|
||||
0xD407
|
||||
|
||||
发生诊断错误
|
||||
|
||||
0xD408
|
||||
|
||||
更新已中止
|
||||
|
||||
0xD409
|
||||
|
||||
DP总线错误
|
||||
|
||||
0xD601
|
||||
|
||||
函数参数中的语法错误
|
||||
|
||||
0xD602
|
||||
|
||||
输入的密码不正确
|
||||
|
||||
0xD603
|
||||
|
||||
连接已合法化
|
||||
|
||||
0xD604
|
||||
|
||||
已启用连接
|
||||
|
||||
0xD605
|
||||
|
||||
由于密码不存在,因此无法进行合法化
|
||||
|
||||
0xD801
|
||||
|
||||
至少有一个标记地址无效
|
||||
|
||||
0xD802
|
||||
|
||||
指定的作业不存在
|
||||
|
||||
0xD803
|
||||
|
||||
非法的工作状态
|
||||
|
||||
0xD804
|
||||
|
||||
非法循环时间(非法时基或多个)
|
||||
|
||||
0xD805
|
||||
|
||||
不能再设置循环读取作业
|
||||
|
||||
0xD806
|
||||
|
||||
引用的作业处于无法执行请求的功能的状态
|
||||
|
||||
0xD807
|
||||
|
||||
功能因过载而中止,这意味着执行读取周期所需的时间比设置的扫描周期时间长
|
||||
|
||||
0xDC01
|
||||
|
||||
日期和/或时间无效
|
||||
|
||||
0xE201
|
||||
|
||||
CPU已经是主设备
|
||||
|
||||
0xE202
|
||||
|
||||
由于闪存模块中的用户程序不同,无法进行连接和更新
|
||||
|
||||
0xE203
|
||||
|
||||
由于固件不同,无法连接和更新
|
||||
|
||||
0xE204
|
||||
|
||||
由于内存配置不同,无法连接和更新
|
||||
|
||||
0xE205
|
||||
|
||||
由于同步错误导致连接/更新中止
|
||||
|
||||
0xE206
|
||||
|
||||
由于协调违规而拒绝连接/更新
|
||||
|
||||
0xEF01
|
||||
|
||||
S7协议错误:ID2错误; 工作中只允许00H
|
||||
|
||||
0xEF02
|
||||
|
||||
S7协议错误:ID2错误; 资源集不存在
|
||||
@@ -207,7 +207,7 @@ public interface IReadWrite : IDisposable
|
||||
/// <summary>
|
||||
/// 读写超时时间
|
||||
/// </summary>
|
||||
ushort TimeOut { get; set; }
|
||||
int TimeOut { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 一个寄存器所占的字节长度
|
||||
|
||||
@@ -54,7 +54,7 @@ public abstract class ReadWriteDevicesBase : IReadWrite
|
||||
|
||||
/// <inheritdoc/>
|
||||
[Description("读写超时时间")]
|
||||
public ushort TimeOut { get; set; } = 3000;
|
||||
public int TimeOut { get; set; } = 3000;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool CascadeDisposal { get; set; } = true;
|
||||
|
||||
@@ -55,7 +55,8 @@ public abstract class ReadWriteDevicesTcpServerBase : ReadWriteDevicesBase
|
||||
/// <inheritdoc/>
|
||||
public override Task ConnectAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
return Task.Run(() => TcpService.Start());
|
||||
Connect(cancellationToken);
|
||||
return EasyTask.CompletedTask;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using System.Text;
|
||||
|
||||
using ThingsGateway.Foundation.Extension.Generic;
|
||||
|
||||
namespace ThingsGateway.Foundation.Core;
|
||||
@@ -19,6 +21,10 @@ namespace ThingsGateway.Foundation.Core;
|
||||
/// </summary>
|
||||
public abstract class ReadWriteDevicesTcpDataHandleAdapter<TRequest> : CustomDataHandlingAdapter<TRequest> where TRequest : class, IMessage
|
||||
{
|
||||
/// <summary>
|
||||
/// 报文输出时采用字符串还是HexString
|
||||
/// </summary>
|
||||
public virtual bool IsHexData { get; set; } = true;
|
||||
/// <inheritdoc cref="ReadWriteDevicesTcpDataHandleAdapter{TRequest}"/>
|
||||
public ReadWriteDevicesTcpDataHandleAdapter()
|
||||
{
|
||||
@@ -46,7 +52,7 @@ public abstract class ReadWriteDevicesTcpDataHandleAdapter<TRequest> : CustomDat
|
||||
{
|
||||
//获取全部内容
|
||||
var allBytes = byteBlock.ToArray(0, byteBlock.Len);
|
||||
Logger?.Trace($"{FoundationConst.LogMessageHeader}{ToString()}- 接收:{allBytes.ToHexString(' ')}");
|
||||
Logger?.Trace($"{FoundationConst.LogMessageHeader}{ToString()}- 接收:{(IsHexData ? allBytes.ToHexString(' ') : Encoding.UTF8.GetString(allBytes))}");
|
||||
//缓存/不缓存解析一样,因为游标已经归0
|
||||
{
|
||||
request = Request;
|
||||
@@ -131,7 +137,7 @@ public abstract class ReadWriteDevicesTcpDataHandleAdapter<TRequest> : CustomDat
|
||||
/// <summary>
|
||||
/// 发送方法,会重新建立<see cref="Request"/>
|
||||
/// </summary>
|
||||
protected void GoSend(byte[] item)
|
||||
protected virtual void GoSend(byte[] item)
|
||||
{
|
||||
byte[] bytes;
|
||||
if (IsSendPackCommand)
|
||||
@@ -141,12 +147,12 @@ public abstract class ReadWriteDevicesTcpDataHandleAdapter<TRequest> : CustomDat
|
||||
Request = GetInstance();
|
||||
Request.SendBytes = bytes;
|
||||
GoSend(bytes, 0, bytes.Length);
|
||||
Logger?.Trace($"{FoundationConst.LogMessageHeader}{ToString()}- 发送:{Request.SendBytes.ToHexString(' ')}");
|
||||
Logger?.Trace($"{FoundationConst.LogMessageHeader}{ToString()}- 发送:{(IsHexData ? Request.SendBytes.ToHexString(' ') : Encoding.UTF8.GetString(Request.SendBytes))}");
|
||||
}
|
||||
/// <summary>
|
||||
/// 发送方法,会重新建立<see cref="Request"/>
|
||||
/// </summary>
|
||||
protected async Task GoSendAsync(byte[] item)
|
||||
protected virtual async Task GoSendAsync(byte[] item)
|
||||
{
|
||||
byte[] bytes;
|
||||
if (IsSendPackCommand)
|
||||
@@ -156,7 +162,7 @@ public abstract class ReadWriteDevicesTcpDataHandleAdapter<TRequest> : CustomDat
|
||||
Request = GetInstance();
|
||||
Request.SendBytes = bytes;
|
||||
await GoSendAsync(bytes, 0, bytes.Length);
|
||||
Logger?.Trace($"{FoundationConst.LogMessageHeader}{ToString()}- 发送:{Request.SendBytes.ToHexString(' ')}");
|
||||
Logger?.Trace($"{FoundationConst.LogMessageHeader}{ToString()}- 发送:{(IsHexData ? Request.SendBytes.ToHexString(' ') : Encoding.UTF8.GetString(Request.SendBytes))}");
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
@@ -180,6 +186,13 @@ public abstract class ReadWriteDevicesTcpDataHandleAdapter<TRequest> : CustomDat
|
||||
/// <inheritdoc/>
|
||||
public override string ToString()
|
||||
{
|
||||
return Owner.ToString();
|
||||
if (Owner is SocketClient client)
|
||||
{
|
||||
return client.GetIPPort();
|
||||
}
|
||||
else
|
||||
{
|
||||
return Owner.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@
|
||||
#endregion
|
||||
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
|
||||
using ThingsGateway.Foundation.Extension.Generic;
|
||||
|
||||
@@ -21,6 +22,13 @@ namespace ThingsGateway.Foundation.Core;
|
||||
/// </summary>
|
||||
public abstract class ReadWriteDevicesUdpDataHandleAdapter<TRequest> : UdpDataHandlingAdapter where TRequest : class, IMessage
|
||||
{
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 报文输出时采用字符串还是HexString
|
||||
/// </summary>
|
||||
public virtual bool IsHexData { get; set; } = true;
|
||||
|
||||
/// <inheritdoc cref="ReadWriteDevicesUdpDataHandleAdapter{TRequest}"/>
|
||||
public ReadWriteDevicesUdpDataHandleAdapter()
|
||||
{
|
||||
@@ -68,13 +76,13 @@ public abstract class ReadWriteDevicesUdpDataHandleAdapter<TRequest> : UdpDataHa
|
||||
Request = GetInstance();
|
||||
Request.SendBytes = bytes;
|
||||
GoSend(endPoint, bytes, 0, bytes.Length);
|
||||
Logger?.Trace($"{FoundationConst.LogMessageHeader}{ToString()}- 发送:{Request.SendBytes.ToHexString(' ')}");
|
||||
Logger?.Trace($"{FoundationConst.LogMessageHeader}{ToString()}- 发送:{(IsHexData ? Request.SendBytes.ToHexString(' ') : Encoding.UTF8.GetString(Request.SendBytes))}");
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
protected override void PreviewReceived(EndPoint remoteEndPoint, ByteBlock byteBlock)
|
||||
{
|
||||
var allBytes = byteBlock.ToArray(0, byteBlock.Len);
|
||||
Logger?.Trace($"{FoundationConst.LogMessageHeader}{ToString()}- 接收:{allBytes.ToHexString(' ')}");
|
||||
Logger?.Trace($"{FoundationConst.LogMessageHeader}{ToString()}- 接收:{(IsHexData ? allBytes.ToHexString(' ') : Encoding.UTF8.GetString(allBytes))}");
|
||||
|
||||
if (Request?.SendBytes == null)
|
||||
{
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using System.Text;
|
||||
|
||||
using ThingsGateway.Foundation.Extension.Generic;
|
||||
|
||||
namespace ThingsGateway.Foundation.Core;
|
||||
@@ -17,6 +19,39 @@ namespace ThingsGateway.Foundation.Core;
|
||||
/// <inheritdoc/>
|
||||
public static class ByteExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取异或校验
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
/// <param name="left"></param>
|
||||
/// <param name="right"></param>
|
||||
/// <returns></returns>
|
||||
public static byte[] GetAsciiXOR(this byte[] data, int left, int right)
|
||||
{
|
||||
int tmp = data[left];
|
||||
for (int i = left + 1; i < data.Length - right; i++)
|
||||
{
|
||||
tmp = (tmp ^ data[i]);
|
||||
}
|
||||
|
||||
byte[] fcs = new byte[2];
|
||||
fcs[0] = Encoding.ASCII.GetBytes(((byte)tmp).ToString("X2"))[0];
|
||||
fcs[1] = Encoding.ASCII.GetBytes(((byte)tmp).ToString("X2"))[1];
|
||||
return fcs;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 数组内容分别相加某个数字
|
||||
/// </summary>
|
||||
/// <param name="bytes"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static byte[] BytesAdd(this byte[] bytes, int value)
|
||||
{
|
||||
for (int index = 0; index < bytes.Length; ++index)
|
||||
bytes[index] = (byte)(bytes[index] + value);
|
||||
return bytes;
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取byte数据类型的第offset位,是否为True<br />
|
||||
/// </summary>
|
||||
|
||||
@@ -72,4 +72,28 @@ namespace ThingsGateway.Foundation.Core
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
#if NET6_0_OR_GREATER
|
||||
public partial class DisposableObject : IAsyncDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// 异步释放资源。内部已经处理了<see cref="GC.SuppressFinalize(object)"/>
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async ValueTask DisposeAsync()
|
||||
{
|
||||
await DisposeAsyncCore().ConfigureAwait(false);
|
||||
Dispose(disposing: false);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步释放资源。注意:此方法仅在调用<see cref="IAsyncDisposable.DisposeAsync"/>时有效。
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected virtual ValueTask DisposeAsyncCore()
|
||||
{
|
||||
return ValueTask.CompletedTask;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:http://rrqm_home.gitee.io/touchsocket/
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace ThingsGateway.Foundation.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// ConfigEventArgs
|
||||
/// </summary>
|
||||
public class ConfigEventArgs : PluginEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// ConfigEventArgs
|
||||
/// </summary>
|
||||
/// <param name="config"></param>
|
||||
public ConfigEventArgs(TouchSocketConfig config)
|
||||
{
|
||||
this.Config = config;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 具体配置
|
||||
/// </summary>
|
||||
public TouchSocketConfig Config { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
#region copyright
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
@@ -10,24 +10,17 @@
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace ThingsGateway.Foundation.Serial;
|
||||
|
||||
/// <summary>
|
||||
/// 通讯基类
|
||||
/// </summary>
|
||||
public abstract class BaseSerial : DependencyObject, ISerial
|
||||
namespace ThingsGateway.Foundation.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// 同步根。
|
||||
/// 具有配置设置的对象
|
||||
/// </summary>
|
||||
protected readonly object SyncRoot = new object();
|
||||
public abstract class ConfigObject : DependencyObject, IConfigObject
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public abstract TouchSocketConfig Config { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public abstract int SendBufferSize { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public abstract int ReceiveBufferSize { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ILog Logger { get; set; }
|
||||
/// <inheritdoc/>
|
||||
public ILog Logger { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
namespace ThingsGateway.Foundation.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// 具有配置的对象接口
|
||||
/// </summary>
|
||||
public interface IConfigObject : IDependencyObject, ILoggerObject
|
||||
{
|
||||
/// <summary>
|
||||
/// 设置项
|
||||
/// </summary>
|
||||
TouchSocketConfig Config { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:http://rrqm_home.gitee.io/touchsocket/
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace ThingsGateway.Foundation.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// 当配置Config完成时触发。
|
||||
/// </summary>
|
||||
public interface ILoadedConfigPlugin<in TSender> : IPlugin where TSender : IConfigObject
|
||||
{
|
||||
/// <summary>
|
||||
/// 当完成配置载入时
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
/// <returns></returns>
|
||||
Task OnLoadedConfig(TSender sender, ConfigEventArgs e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当配置Config完成时触发。
|
||||
/// </summary>
|
||||
public interface ILoadedConfigPlugin : ILoadedConfigPlugin<IConfigObject>
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace ThingsGateway.Foundation.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// 当正在配置Config时触发。
|
||||
/// </summary>
|
||||
public interface ILoadingConfigPlugin<in TSender> : IPlugin where TSender : IConfigObject
|
||||
{
|
||||
/// <summary>
|
||||
/// 当载入配置时
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
Task OnLoadingConfig(TSender sender, ConfigEventArgs e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ILoadingConfigPlugin
|
||||
/// </summary>
|
||||
public interface ILoadingConfigPlugin : ILoadingConfigPlugin<IConfigObject>
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace ThingsGateway.Foundation.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// 具有设置配置的对象接口
|
||||
/// </summary>
|
||||
public interface ISetupConfigObject : IConfigObject, IPluginObject
|
||||
{
|
||||
/// <summary>
|
||||
/// 配置设置项
|
||||
/// </summary>
|
||||
/// <param name="config"></param>
|
||||
/// <exception cref="Exception"></exception>
|
||||
void Setup(TouchSocketConfig config);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace ThingsGateway.Foundation.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// 具有设置配置的对象
|
||||
/// </summary>
|
||||
public abstract class SetupConfigObject : ConfigObject, ISetupConfigObject
|
||||
{
|
||||
private TouchSocketConfig m_config;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override TouchSocketConfig Config => this.m_config;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IContainer Container { get; private set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IPluginsManager PluginsManager { get; private set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Setup(TouchSocketConfig config)
|
||||
{
|
||||
if (config == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(config));
|
||||
}
|
||||
|
||||
this.ThrowIfDisposed();
|
||||
|
||||
this.BuildConfig(config);
|
||||
|
||||
this.PluginsManager?.Raise(nameof(ILoadingConfigPlugin.OnLoadingConfig), this, new ConfigEventArgs(config));
|
||||
this.LoadConfig(this.Config);
|
||||
this.PluginsManager?.Raise(nameof(ILoadedConfigPlugin.OnLoadedConfig), this, new ConfigEventArgs(config));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 加载配置
|
||||
/// </summary>
|
||||
/// <param name="config"></param>
|
||||
protected virtual void LoadConfig(TouchSocketConfig config)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private void BuildConfig(TouchSocketConfig config)
|
||||
{
|
||||
this.m_config = config;
|
||||
|
||||
if (!config.TryGetValue(TouchSocketCoreConfigExtension.ContainerProperty, out var container))
|
||||
{
|
||||
container = new Container();
|
||||
}
|
||||
|
||||
if (!container.IsRegistered(typeof(ILog)))
|
||||
{
|
||||
container.RegisterSingleton<ILog, LoggerGroup>();
|
||||
}
|
||||
|
||||
if (!(config.GetValue(TouchSocketCoreConfigExtension.PluginsManagerProperty) is IPluginsManager pluginsManager))
|
||||
{
|
||||
pluginsManager = new PluginsManager(container);
|
||||
}
|
||||
|
||||
if (container.IsRegistered(typeof(IPluginsManager)))
|
||||
{
|
||||
pluginsManager = container.Resolve<IPluginsManager>();
|
||||
}
|
||||
else
|
||||
{
|
||||
container.RegisterSingleton<IPluginsManager>(pluginsManager);
|
||||
}
|
||||
|
||||
if (config.GetValue(TouchSocketCoreConfigExtension.ConfigureContainerProperty) is Action<IContainer> actionContainer)
|
||||
{
|
||||
actionContainer.Invoke(container);
|
||||
}
|
||||
|
||||
if (config.GetValue(TouchSocketCoreConfigExtension.ConfigurePluginsProperty) is Action<IPluginsManager> actionPluginsManager)
|
||||
{
|
||||
pluginsManager.Enable = true;
|
||||
actionPluginsManager.Invoke(pluginsManager);
|
||||
}
|
||||
|
||||
this.Logger ??= container.Resolve<ILog>();
|
||||
|
||||
this.Container = container;
|
||||
this.PluginsManager = pluginsManager;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -28,8 +28,22 @@ namespace ThingsGateway.Foundation.Core
|
||||
/// <summary>
|
||||
/// 配置文件基类
|
||||
/// </summary>
|
||||
public class TouchSocketConfig : DependencyObject
|
||||
public class TouchSocketConfig : DependencyObject, ICloneable
|
||||
{
|
||||
/// <summary>
|
||||
/// 克隆配置依赖项,并返回一个新的克隆对象。
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public TouchSocketConfig Clone()
|
||||
{
|
||||
var config = new TouchSocketConfig();
|
||||
this.CloneTo(config, true);
|
||||
return config;
|
||||
}
|
||||
|
||||
object ICloneable.Clone()
|
||||
{
|
||||
return this.Clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -28,17 +28,17 @@ namespace ThingsGateway.Foundation.Core
|
||||
/// <summary>
|
||||
/// 单线程流式适配器配置
|
||||
/// </summary>
|
||||
public class SingleStreamAdapterOption
|
||||
public class AdapterOption
|
||||
{
|
||||
/// <summary>
|
||||
/// 适配器数据包缓存启用。默认为缺省(null),如果有正常值会在设置适配器时,直接作用于<see cref="SingleStreamDataHandlingAdapter.CacheTimeout"/>
|
||||
/// </summary>
|
||||
public bool? CacheTimeoutEnable { get; set; } = true;
|
||||
public bool? CacheTimeoutEnable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 适配器数据包缓存时长。默认为缺省(null)。当该值有效时会在设置适配器时,直接作用于<see cref="SingleStreamDataHandlingAdapter.CacheTimeout"/>
|
||||
/// </summary>
|
||||
public int? CacheTimeout { get; set; }
|
||||
public TimeSpan? CacheTimeout { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 适配器数据包最大值。默认缺省(null),当该值有效时会在设置适配器时,直接作用于<see cref="DataHandlingAdapter.MaxPackageSize"/>
|
||||
@@ -103,12 +103,12 @@ namespace ThingsGateway.Foundation.Core
|
||||
{
|
||||
return FilterResult.Cache;
|
||||
}
|
||||
if (!requestInfo.OnParsingStartCode(byteBlock.ToArray(byteBlock.Pos, this.StartCode.Length)))
|
||||
if (!requestInfo.OnParsingStartCode(byteBlock.ToArray(byteBlock.Pos + indexStart + 1 - this.StartCode.Length, this.StartCode.Length)))
|
||||
{
|
||||
byteBlock.Pos += this.StartCode.Length;
|
||||
byteBlock.Pos += indexStart;
|
||||
return FilterResult.GoOn;
|
||||
}
|
||||
byteBlock.Pos += this.StartCode.Length;
|
||||
byteBlock.Pos += indexStart + 1;
|
||||
request = requestInfo;
|
||||
|
||||
int len;
|
||||
|
||||
@@ -26,92 +26,62 @@ namespace ThingsGateway.Foundation.Core
|
||||
/// <param name="config"></param>
|
||||
public static void Config(this SingleStreamDataHandlingAdapter adapter, TouchSocketConfig config)
|
||||
{
|
||||
if (config.GetValue(DataHandlingAdapterExtension.MaxPackageSizeProperty) is int v1)
|
||||
var option = config.GetValue(AdapterOptionProperty) ?? throw new ArgumentNullException(nameof(AdapterOptionProperty));
|
||||
|
||||
if (option.MaxPackageSize.HasValue)
|
||||
{
|
||||
adapter.MaxPackageSize = v1;
|
||||
adapter.MaxPackageSize = option.MaxPackageSize.Value;
|
||||
}
|
||||
if (config.GetValue(DataHandlingAdapterExtension.CacheTimeoutProperty) != TimeSpan.Zero)
|
||||
|
||||
if (option.CacheTimeout.HasValue)
|
||||
{
|
||||
adapter.CacheTimeout = config.GetValue(DataHandlingAdapterExtension.CacheTimeoutProperty);
|
||||
adapter.CacheTimeout = option.CacheTimeout.Value;
|
||||
}
|
||||
if (config.GetValue(DataHandlingAdapterExtension.CacheTimeoutEnableProperty) is bool v2)
|
||||
|
||||
if (option.CacheTimeoutEnable.HasValue)
|
||||
{
|
||||
adapter.CacheTimeoutEnable = v2;
|
||||
adapter.CacheTimeoutEnable = option.CacheTimeoutEnable.Value;
|
||||
}
|
||||
if (config.GetValue(DataHandlingAdapterExtension.UpdateCacheTimeWhenRevProperty) is bool v3)
|
||||
|
||||
if (option.UpdateCacheTimeWhenRev.HasValue)
|
||||
{
|
||||
adapter.UpdateCacheTimeWhenRev = v3;
|
||||
adapter.UpdateCacheTimeWhenRev = option.UpdateCacheTimeWhenRev.Value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将<see cref="TouchSocketConfig"/>中的配置,装载在<see cref="SingleStreamDataHandlingAdapter"/>上。
|
||||
/// </summary>
|
||||
/// <param name="adapter"></param>
|
||||
/// <param name="config"></param>
|
||||
public static void Config(this DataHandlingAdapter adapter, TouchSocketConfig config)
|
||||
{
|
||||
var option = config.GetValue(AdapterOptionProperty) ?? throw new ArgumentNullException(nameof(AdapterOptionProperty));
|
||||
|
||||
if (option.MaxPackageSize.HasValue)
|
||||
{
|
||||
adapter.MaxPackageSize = option.MaxPackageSize.Value;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 适配器配置
|
||||
|
||||
/// <summary>
|
||||
/// 适配器数据包缓存启用。默认为缺省(null),如果有正常值会在设置适配器时,直接作用于<see cref="SingleStreamDataHandlingAdapter.CacheTimeout"/>
|
||||
/// 设置适配器相关的配置
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty<bool?> CacheTimeoutEnableProperty = DependencyProperty<bool?>.Register("CacheTimeoutEnable", null);
|
||||
public static readonly DependencyProperty<AdapterOption> AdapterOptionProperty = DependencyProperty<AdapterOption>.Register("AdapterOption", new AdapterOption());
|
||||
|
||||
/// <summary>
|
||||
/// 适配器数据包缓存时长。默认为缺省(<see cref="TimeSpan.Zero"/>)。当该值有效时会在设置适配器时,直接作用于<see cref="SingleStreamDataHandlingAdapter.CacheTimeout"/>
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty<TimeSpan> CacheTimeoutProperty = DependencyProperty<TimeSpan>.Register("CacheTimeout", TimeSpan.Zero);
|
||||
|
||||
/// <summary>
|
||||
/// 适配器数据包最大值。默认缺省(null),当该值有效时会在设置适配器时,直接作用于<see cref="DataHandlingAdapter.MaxPackageSize"/>
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty<int?> MaxPackageSizeProperty = DependencyProperty<int?>.Register("MaxPackageSize", null);
|
||||
|
||||
/// <summary>
|
||||
/// 适配器数据包缓存策略。默认缺省(null),当该值有效时会在设置适配器时,直接作用于<see cref="SingleStreamDataHandlingAdapter.UpdateCacheTimeWhenRev"/>
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty<bool?> UpdateCacheTimeWhenRevProperty = DependencyProperty<bool?>.Register("UpdateCacheTimeWhenRev", null);
|
||||
|
||||
/// <summary>
|
||||
/// 适配器数据包缓存时长。默认为缺省(<see cref="TimeSpan.Zero"/>)。当该值有效时会在设置适配器时,直接作用于<see cref="SingleStreamDataHandlingAdapter.CacheTimeout"/>
|
||||
/// 设置适配器相关的配置
|
||||
/// </summary>
|
||||
/// <param name="config"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static TouchSocketConfig SetCacheTimeout(this TouchSocketConfig config, TimeSpan value)
|
||||
public static TouchSocketConfig SetAdapterOption(this TouchSocketConfig config, AdapterOption value)
|
||||
{
|
||||
config.SetValue(CacheTimeoutProperty, value);
|
||||
return config;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 适配器数据包缓存启用。默认为缺省(null),如果有正常值会在设置适配器时,直接作用于<see cref="SingleStreamDataHandlingAdapter.CacheTimeoutEnable"/>
|
||||
/// </summary>
|
||||
/// <param name="config"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static TouchSocketConfig SetCacheTimeoutEnable(this TouchSocketConfig config, bool value)
|
||||
{
|
||||
config.SetValue(CacheTimeoutEnableProperty, value);
|
||||
return config;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 适配器数据包最大值。默认缺省(null),当该值有效时会在设置适配器时,直接作用于<see cref="DataHandlingAdapter.MaxPackageSize"/>
|
||||
/// </summary>
|
||||
/// <param name="config"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static TouchSocketConfig SetMaxPackageSize(this TouchSocketConfig config, int value)
|
||||
{
|
||||
config.SetValue(MaxPackageSizeProperty, value);
|
||||
return config;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 适配器数据包缓存策略。默认缺省(null),当该值有效时会在设置适配器时,直接作用于<see cref="SingleStreamDataHandlingAdapter.UpdateCacheTimeWhenRev"/>
|
||||
/// </summary>
|
||||
/// <param name="config"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static TouchSocketConfig SetUpdateCacheTimeWhenRev(this TouchSocketConfig config, bool value)
|
||||
{
|
||||
config.SetValue(UpdateCacheTimeWhenRevProperty, value);
|
||||
config.SetValue(AdapterOptionProperty, value);
|
||||
return config;
|
||||
}
|
||||
|
||||
|
||||
@@ -96,5 +96,45 @@ namespace ThingsGateway.Foundation.Core
|
||||
this.m_dp.Clear();
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 将当前对象的依赖项克隆到目标对象中
|
||||
/// </summary>
|
||||
/// <param name="dependencyObject">目标对象</param>
|
||||
/// <param name="overwrite">当目标对象中存在相同依赖项时,是或否覆盖</param>
|
||||
/// <exception cref="ArgumentNullException"></exception>
|
||||
/// <exception cref="ObjectDisposedException"></exception>
|
||||
protected void CloneTo(DependencyObject dependencyObject, bool overwrite)
|
||||
{
|
||||
if (dependencyObject is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(dependencyObject));
|
||||
}
|
||||
|
||||
if (dependencyObject.DisposedValue)
|
||||
{
|
||||
throw new ObjectDisposedException(nameof(dependencyObject));
|
||||
}
|
||||
|
||||
this.ThrowIfDisposed();
|
||||
|
||||
foreach (var item in this.m_dp)
|
||||
{
|
||||
if (dependencyObject.m_dp.ContainsKey(item.Key))
|
||||
{
|
||||
if (overwrite)
|
||||
{
|
||||
dependencyObject.m_dp.Remove(item.Key);
|
||||
dependencyObject.m_dp.Add(item.Key, item.Value);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dependencyObject.m_dp.Add(item.Key, item.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -189,7 +189,7 @@ namespace ThingsGateway.Foundation.Core
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<string> GetTupleElementNames(this ParameterInfo parameter)
|
||||
{
|
||||
return ((dynamic)parameter.GetCustomAttribute(Type.GetType("System.Runtime.CompilerServices.TupleElementNamesAttribute")))?.TransformNames;
|
||||
return (IEnumerable<string>)DynamicMethodMemberAccessor.Default.GetValue(parameter.GetCustomAttribute(Type.GetType("System.Runtime.CompilerServices.TupleElementNamesAttribute")), "TransformNames");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -199,7 +199,7 @@ namespace ThingsGateway.Foundation.Core
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<string> GetTupleElementNames(this MemberInfo memberInfo)
|
||||
{
|
||||
return ((dynamic)memberInfo.GetCustomAttribute(Type.GetType("System.Runtime.CompilerServices.TupleElementNamesAttribute")))?.TransformNames;
|
||||
return (IEnumerable<string>)DynamicMethodMemberAccessor.Default.GetValue(memberInfo.GetCustomAttribute(Type.GetType("System.Runtime.CompilerServices.TupleElementNamesAttribute")), "TransformNames");
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -73,5 +73,47 @@ namespace ThingsGateway.Foundation.Core
|
||||
return task.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步等待指定最大时间
|
||||
/// </summary>
|
||||
/// <typeparam name="TResult"></typeparam>
|
||||
/// <param name="task"></param>
|
||||
/// <param name="timeout"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="TimeoutException"></exception>
|
||||
public static async Task<TResult> WaitAsync<TResult>(this Task<TResult> task, TimeSpan timeout)
|
||||
{
|
||||
using (var timeoutCancellationTokenSource = new CancellationTokenSource())
|
||||
{
|
||||
var delayTask = Task.Delay(timeout, timeoutCancellationTokenSource.Token);
|
||||
if (await Task.WhenAny(task, delayTask) == task)
|
||||
{
|
||||
timeoutCancellationTokenSource.Cancel();
|
||||
return await task;
|
||||
}
|
||||
throw new TimeoutException();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步等待指定最大时间
|
||||
/// </summary>
|
||||
/// <param name="task"></param>
|
||||
/// <param name="timeout"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="TimeoutException"></exception>
|
||||
public static async Task WaitAsync(this Task task, TimeSpan timeout)
|
||||
{
|
||||
using (var timeoutCancellationTokenSource = new CancellationTokenSource())
|
||||
{
|
||||
var delayTask = Task.Delay(timeout, timeoutCancellationTokenSource.Token);
|
||||
if (await Task.WhenAny(task, delayTask) == task)
|
||||
{
|
||||
timeoutCancellationTokenSource.Cancel();
|
||||
await task;
|
||||
}
|
||||
throw new TimeoutException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,22 +23,16 @@
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace ThingsGateway.Foundation.Rpc
|
||||
namespace ThingsGateway.Foundation.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// 函数标识
|
||||
/// 具有日志记录器的对象接口
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum MethodFlags
|
||||
public interface ILoggerObject
|
||||
{
|
||||
/// <summary>
|
||||
/// 空
|
||||
/// 日志记录器
|
||||
/// </summary>
|
||||
None = 1,
|
||||
|
||||
/// <summary>
|
||||
/// 包含调用上下文
|
||||
/// </summary>
|
||||
IncludeCallContext = 2
|
||||
ILog Logger { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@
|
||||
#endregion
|
||||
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
#if NET6_0_OR_GREATER
|
||||
using System.Numerics;
|
||||
@@ -55,12 +56,11 @@ namespace ThingsGateway.Foundation.Core
|
||||
}
|
||||
|
||||
var capacity = 0L;
|
||||
var poolId = this.Id;
|
||||
var maxBuckets = SelectBucketIndex(maxArrayLength);
|
||||
var buckets = new Bucket[maxBuckets + 1];
|
||||
for (var i = 0; i < buckets.Length; i++)
|
||||
{
|
||||
buckets[i] = new Bucket(GetMaxSizeForBucket(i), maxArraysPerBucket, poolId);
|
||||
buckets[i] = new Bucket(GetMaxSizeForBucket(i), maxArraysPerBucket);
|
||||
long num = GetMaxSizeForBucket(i) * maxArraysPerBucket;
|
||||
capacity += num;
|
||||
}
|
||||
@@ -183,16 +183,19 @@ namespace ThingsGateway.Foundation.Core
|
||||
/// </summary>
|
||||
/// <param name="size"></param>
|
||||
/// <returns></returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static int HitSize(int size)
|
||||
{
|
||||
return GetMaxSizeForBucket(SelectBucketIndex(size));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static int GetMaxSizeForBucket(int binIndex)
|
||||
{
|
||||
return 16 << binIndex;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static int SelectBucketIndex(int bufferSize)
|
||||
{
|
||||
#if NET6_0_OR_GREATER
|
||||
@@ -208,18 +211,16 @@ namespace ThingsGateway.Foundation.Core
|
||||
internal readonly int m_bufferLength;
|
||||
private readonly int m_numberOfBuffers;
|
||||
private T[][] m_buffers;
|
||||
private readonly int m_poolId;
|
||||
|
||||
private int m_index;
|
||||
private SpinLock m_lock;
|
||||
|
||||
internal Bucket(int bufferLength, int numberOfBuffers, int poolId)
|
||||
internal Bucket(int bufferLength, int numberOfBuffers)
|
||||
{
|
||||
this.m_lock = new SpinLock(Debugger.IsAttached);
|
||||
this.m_buffers = new T[numberOfBuffers][];
|
||||
this.m_bufferLength = bufferLength;
|
||||
this.m_numberOfBuffers = numberOfBuffers;
|
||||
this.m_poolId = poolId;
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace ThingsGateway.Foundation.Core
|
||||
/// <summary>
|
||||
/// 内存池
|
||||
/// </summary>
|
||||
public class BytePool : ArrayPool<byte>
|
||||
public sealed class BytePool : ArrayPool<byte>
|
||||
{
|
||||
private readonly Timer m_timer;
|
||||
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:http://rrqm_home.gitee.io/touchsocket/
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace ThingsGateway.Foundation.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// 序列化器
|
||||
/// </summary>
|
||||
/// <typeparam name="TSource"></typeparam>
|
||||
public interface ISerializer<TSource>
|
||||
{
|
||||
/// <summary>
|
||||
/// 序列化
|
||||
/// </summary>
|
||||
/// <param name="target"></param>
|
||||
/// <returns></returns>
|
||||
TSource Serialize(object target);
|
||||
|
||||
/// <summary>
|
||||
/// 反序列化
|
||||
/// </summary>
|
||||
/// <param name="source"></param>
|
||||
/// <param name="targetType"></param>
|
||||
/// <returns></returns>
|
||||
object Deserialize(TSource source, Type targetType);
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@ namespace ThingsGateway.Foundation.Dmtp
|
||||
/// <summary>
|
||||
/// 提供Dmtp协议的最基础功能件
|
||||
/// </summary>
|
||||
public interface IDmtpActor : IDependencyObject
|
||||
public interface IDmtpActor : IDependencyObject, IHandshakeObject
|
||||
{
|
||||
#region 属性
|
||||
|
||||
@@ -39,11 +39,6 @@ namespace ThingsGateway.Foundation.Dmtp
|
||||
/// </summary>
|
||||
string Id { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前功能件是否已经完成握手连接状态。
|
||||
/// </summary>
|
||||
bool IsHandshaked { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 最后一次活动时间。
|
||||
/// </summary>
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:http://rrqm_home.gitee.io/touchsocket/
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace ThingsGateway.Foundation.Dmtp
|
||||
{
|
||||
/// <summary>
|
||||
/// 针对Dmtp的配置项
|
||||
/// </summary>
|
||||
public class DmtpOption
|
||||
{
|
||||
/// <summary>
|
||||
/// 连接令箭
|
||||
/// </summary>
|
||||
public string VerifyToken { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 连接时指定Id。
|
||||
/// <para>
|
||||
/// 使用该功能时,仅在服务器的Handshaking之后生效。且如果id重复,则会连接失败。
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public string Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 设置DmtpClient连接时的元数据
|
||||
/// </summary>
|
||||
public Metadata Metadata { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 验证连接超时时间。仅用于服务器。意为:当服务器收到基础链接,在指定的时间内如果没有收到握手信息,则直接视为无效链接,直接断开。
|
||||
/// </summary>
|
||||
public TimeSpan VerifyTimeout { get; set; } = TimeSpan.FromSeconds(3);
|
||||
}
|
||||
}
|
||||
@@ -70,7 +70,7 @@ namespace ThingsGateway.Foundation.Dmtp
|
||||
/// <summary>
|
||||
/// 最大传输速度。
|
||||
/// </summary>
|
||||
public long MaxSpeed { get => this.m_flowGate.Maximum; set => this.m_flowGate.Maximum = value; }
|
||||
public virtual long MaxSpeed { get => this.m_flowGate.Maximum; set => this.m_flowGate.Maximum = value; }
|
||||
|
||||
/// <summary>
|
||||
/// 元数据
|
||||
|
||||
@@ -35,13 +35,13 @@ namespace ThingsGateway.Foundation.Dmtp
|
||||
private bool m_allowRoute;
|
||||
private Func<string, Task<IDmtpActor>> m_findDmtpActor;
|
||||
private DmtpActor m_dmtpActor;
|
||||
private readonly SemaphoreSlim m_semaphore = new SemaphoreSlim(1, 1);
|
||||
private readonly SemaphoreSlim m_semaphoreForConnect = new SemaphoreSlim(1, 1);
|
||||
#endregion 字段
|
||||
|
||||
/// <inheritdoc cref="IDmtpActor.Id"/>
|
||||
public string Id => this.m_dmtpActor.Id;
|
||||
|
||||
/// <inheritdoc cref="IDmtpActor.IsHandshaked"/>
|
||||
/// <inheritdoc cref="IHandshakeObject.IsHandshaked"/>
|
||||
public bool IsHandshaked => this.m_dmtpActor != null && this.m_dmtpActor.IsHandshaked;
|
||||
|
||||
/// <inheritdoc/>
|
||||
@@ -50,22 +50,23 @@ namespace ThingsGateway.Foundation.Dmtp
|
||||
#region 连接
|
||||
|
||||
/// <summary>
|
||||
/// 建立Tcp连接,并且执行握手。
|
||||
/// 使用基于Http升级的协议,连接Dmtp服务器
|
||||
/// </summary>
|
||||
/// <param name="timeout"></param>
|
||||
/// <returns></returns>
|
||||
/// <param name="token"></param>
|
||||
/// <exception cref="Exception"></exception>
|
||||
public override ITcpClient Connect(int timeout = 5000)
|
||||
public override void Connect(int timeout, CancellationToken token)
|
||||
{
|
||||
lock (this.SyncRoot)
|
||||
try
|
||||
{
|
||||
this.m_semaphoreForConnect.Wait(token);
|
||||
if (this.IsHandshaked)
|
||||
{
|
||||
return this;
|
||||
return;
|
||||
}
|
||||
if (!this.Online)
|
||||
{
|
||||
base.Connect(timeout);
|
||||
base.Connect(timeout, token);
|
||||
}
|
||||
|
||||
var request = new HttpRequest()
|
||||
@@ -78,72 +79,41 @@ namespace ThingsGateway.Foundation.Dmtp
|
||||
if (response.StatusCode == 101)
|
||||
{
|
||||
this.SwitchProtocolToDmtp();
|
||||
this.m_dmtpActor.Handshake(this.Config.GetValue(DmtpConfigExtension.VerifyTokenProperty),
|
||||
this.Config.GetValue(DmtpConfigExtension.DefaultIdProperty),
|
||||
timeout, this.Config.GetValue(DmtpConfigExtension.MetadataProperty), CancellationToken.None);
|
||||
return this;
|
||||
this.m_dmtpActor.Handshake(
|
||||
|
||||
this.Config.GetValue(DmtpConfigExtension.DmtpOptionProperty).VerifyToken, this.Config.GetValue(DmtpConfigExtension.DmtpOptionProperty).Id, timeout, this.Config.GetValue(DmtpConfigExtension.DmtpOptionProperty).Metadata, token);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception(response.StatusMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual IHttpDmtpClient Connect(CancellationToken token, int timeout = 5000)
|
||||
{
|
||||
lock (this.SyncRoot)
|
||||
finally
|
||||
{
|
||||
if (this.IsHandshaked)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
if (!this.Online)
|
||||
{
|
||||
base.Connect(timeout);
|
||||
}
|
||||
|
||||
var request = new HttpRequest()
|
||||
.SetHost(this.RemoteIPHost.Host);
|
||||
request.Headers.Add(HttpHeaders.Connection, "upgrade");
|
||||
request.Headers.Add(HttpHeaders.Upgrade, DmtpUtility.Dmtp.ToLower());
|
||||
|
||||
request.AsMethod(DmtpUtility.Dmtp);
|
||||
var response = this.RequestContent(request, timeout: timeout, token: token);
|
||||
if (response.StatusCode == 101)
|
||||
{
|
||||
this.SwitchProtocolToDmtp();
|
||||
this.m_dmtpActor.Handshake(this.Config.GetValue(DmtpConfigExtension.VerifyTokenProperty),
|
||||
this.Config.GetValue(DmtpConfigExtension.DefaultIdProperty),
|
||||
timeout, this.Config.GetValue(DmtpConfigExtension.MetadataProperty), token);
|
||||
return this;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception(response.StatusMessage);
|
||||
}
|
||||
this.m_semaphoreForConnect.Release();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 建立Tcp连接,并且执行握手。
|
||||
/// 异步使用基于Http升级的协议,连接Dmtp服务器
|
||||
/// </summary>
|
||||
/// <param name="timeout"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="Exception"></exception>
|
||||
public override async Task<ITcpClient> ConnectAsync(int timeout = 5000)
|
||||
public override async Task ConnectAsync(int timeout, CancellationToken token)
|
||||
{
|
||||
try
|
||||
{
|
||||
await this.m_semaphore.WaitAsync();
|
||||
await this.m_semaphoreForConnect.WaitAsync(timeout, token);
|
||||
if (this.IsHandshaked)
|
||||
{
|
||||
return this;
|
||||
return;
|
||||
}
|
||||
if (!this.Online)
|
||||
{
|
||||
await base.ConnectAsync(timeout);
|
||||
await base.ConnectAsync(timeout, token);
|
||||
}
|
||||
|
||||
var request = new HttpRequest()
|
||||
@@ -152,14 +122,12 @@ namespace ThingsGateway.Foundation.Dmtp
|
||||
request.Headers.Add(HttpHeaders.Upgrade, DmtpUtility.Dmtp.ToLower());
|
||||
|
||||
request.AsMethod(DmtpUtility.Dmtp);
|
||||
var response = this.RequestContent(request);
|
||||
var response = await this.RequestContentAsync(request);
|
||||
if (response.StatusCode == 101)
|
||||
{
|
||||
this.SwitchProtocolToDmtp();
|
||||
await this.m_dmtpActor.HandshakeAsync(this.Config.GetValue(DmtpConfigExtension.VerifyTokenProperty),
|
||||
this.Config.GetValue(DmtpConfigExtension.DefaultIdProperty),
|
||||
timeout, this.Config.GetValue(DmtpConfigExtension.MetadataProperty), CancellationToken.None);
|
||||
return this;
|
||||
await this.m_dmtpActor.HandshakeAsync(this.Config.GetValue(DmtpConfigExtension.DmtpOptionProperty).VerifyToken, this.Config.GetValue(DmtpConfigExtension.DmtpOptionProperty).Id, timeout, this.Config.GetValue(DmtpConfigExtension.DmtpOptionProperty).Metadata, token);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -168,48 +136,7 @@ namespace ThingsGateway.Foundation.Dmtp
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.m_semaphore.Release();
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual async Task<IHttpDmtpClient> ConnectAsync(CancellationToken token, int timeout = 5000)
|
||||
{
|
||||
try
|
||||
{
|
||||
await this.m_semaphore.WaitAsync();
|
||||
if (this.IsHandshaked)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
if (!this.Online)
|
||||
{
|
||||
await base.ConnectAsync(timeout);
|
||||
}
|
||||
|
||||
var request = new HttpRequest()
|
||||
.SetHost(this.RemoteIPHost.Host);
|
||||
request.Headers.Add(HttpHeaders.Connection, "upgrade");
|
||||
request.Headers.Add(HttpHeaders.Upgrade, DmtpUtility.Dmtp.ToLower());
|
||||
|
||||
request.AsMethod(DmtpUtility.Dmtp);
|
||||
var response = this.RequestContent(request, timeout: timeout, token: token);
|
||||
if (response.StatusCode == 101)
|
||||
{
|
||||
this.SwitchProtocolToDmtp();
|
||||
await this.m_dmtpActor.HandshakeAsync(this.Config.GetValue(DmtpConfigExtension.VerifyTokenProperty),
|
||||
this.Config.GetValue(DmtpConfigExtension.DefaultIdProperty),
|
||||
timeout, this.Config.GetValue(DmtpConfigExtension.MetadataProperty), token);
|
||||
return this;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception(response.StatusMessage);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.m_semaphore.Release();
|
||||
this.m_semaphoreForConnect.Release();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ namespace ThingsGateway.Foundation.Dmtp
|
||||
/// <summary>
|
||||
/// 连接令箭
|
||||
/// </summary>
|
||||
public string VerifyToken => this.Config.GetValue(DmtpConfigExtension.VerifyTokenProperty);
|
||||
public string VerifyToken => this.Config.GetValue(DmtpConfigExtension.DmtpOptionProperty).VerifyToken;
|
||||
|
||||
#region 字段
|
||||
|
||||
|
||||
@@ -40,14 +40,14 @@ namespace ThingsGateway.Foundation.Dmtp
|
||||
public bool IsHandshaked => this.DmtpActor != null && this.DmtpActor.IsHandshaked;
|
||||
|
||||
/// <summary>
|
||||
/// 验证超时时间,默认为3000ms
|
||||
/// 验证超时时间
|
||||
/// </summary>
|
||||
public int VerifyTimeout => this.Config.GetValue(DmtpConfigExtension.VerifyTimeoutProperty);
|
||||
public TimeSpan VerifyTimeout => this.Config.GetValue(DmtpConfigExtension.DmtpOptionProperty).VerifyTimeout;
|
||||
|
||||
/// <summary>
|
||||
/// 连接令箭
|
||||
/// </summary>
|
||||
public string VerifyToken => this.Config.GetValue(DmtpConfigExtension.VerifyTokenProperty);
|
||||
public string VerifyToken => this.Config.GetValue(DmtpConfigExtension.DmtpOptionProperty).VerifyToken;
|
||||
|
||||
#region 断开
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
|
||||
namespace ThingsGateway.Foundation.Dmtp
|
||||
{
|
||||
/// <summary>
|
||||
@@ -18,20 +17,5 @@ namespace ThingsGateway.Foundation.Dmtp
|
||||
/// </summary>
|
||||
public interface IHttpDmtpClient : IHttpClient, IHttpDmtpClientBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 建立Tcp,并发送Http请求,最后完成Dmtp握手连接。
|
||||
/// </summary>
|
||||
/// <param name="token"></param>
|
||||
/// <param name="timeout"></param>
|
||||
/// <returns></returns>
|
||||
IHttpDmtpClient Connect(CancellationToken token, int timeout = 5000);
|
||||
|
||||
/// <summary>
|
||||
/// 建立Tcp,并发送Http请求,最后完成Dmtp握手连接。
|
||||
/// </summary>
|
||||
/// <param name="token"></param>
|
||||
/// <param name="timeout"></param>
|
||||
/// <returns></returns>
|
||||
Task<IHttpDmtpClient> ConnectAsync(CancellationToken token, int timeout = 5000);
|
||||
}
|
||||
}
|
||||
@@ -17,20 +17,6 @@ namespace ThingsGateway.Foundation.Dmtp
|
||||
/// </summary>
|
||||
public interface ITcpDmtpClient : ITcpDmtpClientBase, ITcpClient
|
||||
{
|
||||
/// <summary>
|
||||
/// 建立Tcp连接,并且执行握手。
|
||||
/// </summary>
|
||||
/// <param name="token">可取消令箭</param>
|
||||
/// <param name="timeout">超时时间</param>
|
||||
/// <returns></returns>
|
||||
ITcpDmtpClient Connect(CancellationToken token, int timeout = 5000);
|
||||
|
||||
/// <summary>
|
||||
/// 建立Tcp连接,并且执行握手。
|
||||
/// </summary>
|
||||
/// <param name="token">可取消令箭</param>
|
||||
/// <param name="timeout">超时时间</param>
|
||||
/// <returns></returns>
|
||||
Task<ITcpDmtpClient> ConnectAsync(CancellationToken token, int timeout = 5000);
|
||||
}
|
||||
}
|
||||
@@ -46,14 +46,14 @@ namespace ThingsGateway.Foundation.Dmtp
|
||||
|
||||
#region 字段
|
||||
|
||||
private readonly SemaphoreSlim m_semaphore = new SemaphoreSlim(1, 1);
|
||||
private readonly SemaphoreSlim m_semaphoreForConnect = new SemaphoreSlim(1, 1);
|
||||
private bool m_allowRoute;
|
||||
private SealedDmtpActor m_dmtpActor;
|
||||
private Func<string, Task<IDmtpActor>> m_findDmtpActor;
|
||||
|
||||
#endregion 字段
|
||||
|
||||
/// <inheritdoc cref="IDmtpActor.IsHandshaked"/>
|
||||
/// <inheritdoc cref="IHandshakeObject.IsHandshaked"/>
|
||||
public bool IsHandshaked => this.m_dmtpActor != null && this.m_dmtpActor.IsHandshaked;
|
||||
|
||||
#region 断开
|
||||
@@ -95,98 +95,60 @@ namespace ThingsGateway.Foundation.Dmtp
|
||||
#region 连接
|
||||
|
||||
/// <summary>
|
||||
/// 建立Tcp连接,并且执行握手。
|
||||
/// 进行Dmtp协议的握手连接
|
||||
/// </summary>
|
||||
/// <param name="timeout"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
public override ITcpClient Connect(int timeout = 5000)
|
||||
public override void Connect(int timeout, CancellationToken token)
|
||||
{
|
||||
lock (this.SyncRoot)
|
||||
try
|
||||
{
|
||||
this.m_semaphoreForConnect.Wait(token);
|
||||
if (this.IsHandshaked)
|
||||
{
|
||||
return this;
|
||||
return;
|
||||
}
|
||||
if (!this.Online)
|
||||
{
|
||||
base.Connect(timeout);
|
||||
base.Connect(timeout, token);
|
||||
}
|
||||
|
||||
this.m_dmtpActor.Handshake(this.Config.GetValue(DmtpConfigExtension.VerifyTokenProperty),
|
||||
this.Config.GetValue(DmtpConfigExtension.DefaultIdProperty), timeout, this.Config.GetValue(DmtpConfigExtension.MetadataProperty), CancellationToken.None);
|
||||
return this;
|
||||
this.m_dmtpActor.Handshake(this.Config.GetValue(DmtpConfigExtension.DmtpOptionProperty).VerifyToken,
|
||||
this.Config.GetValue(DmtpConfigExtension.DmtpOptionProperty).Id, timeout, this.Config.GetValue(DmtpConfigExtension.DmtpOptionProperty).Metadata, token);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual ITcpDmtpClient Connect(CancellationToken token, int timeout = 5000)
|
||||
{
|
||||
lock (this.SyncRoot)
|
||||
finally
|
||||
{
|
||||
if (this.IsHandshaked)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
if (!this.Online)
|
||||
{
|
||||
base.Connect(timeout);
|
||||
}
|
||||
|
||||
this.m_dmtpActor.Handshake(this.Config.GetValue(DmtpConfigExtension.VerifyTokenProperty),
|
||||
this.Config.GetValue(DmtpConfigExtension.DefaultIdProperty), timeout, this.Config.GetValue(DmtpConfigExtension.MetadataProperty), token);
|
||||
return this;
|
||||
this.m_semaphoreForConnect.Release();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 建立Tcp连接,并且执行握手。
|
||||
/// 异步进行Dmtp协议的握手连接
|
||||
/// </summary>
|
||||
/// <param name="timeout"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
public override async Task<ITcpClient> ConnectAsync(int timeout = 5000)
|
||||
public override async Task ConnectAsync(int timeout, CancellationToken token)
|
||||
{
|
||||
try
|
||||
{
|
||||
await this.m_semaphore.WaitAsync();
|
||||
await this.m_semaphoreForConnect.WaitAsync(timeout, token);
|
||||
if (this.IsHandshaked)
|
||||
{
|
||||
return this;
|
||||
return;
|
||||
}
|
||||
if (!this.Online)
|
||||
{
|
||||
await base.ConnectAsync(timeout).ConfigureFalseAwait();
|
||||
await base.ConnectAsync(timeout, token);
|
||||
}
|
||||
|
||||
await this.m_dmtpActor.HandshakeAsync(this.Config.GetValue(DmtpConfigExtension.VerifyTokenProperty), this.Config.GetValue(DmtpConfigExtension.DefaultIdProperty), timeout, this.Config.GetValue(DmtpConfigExtension.MetadataProperty), CancellationToken.None).ConfigureFalseAwait();
|
||||
return this;
|
||||
await this.m_dmtpActor.HandshakeAsync(this.Config.GetValue(DmtpConfigExtension.DmtpOptionProperty).VerifyToken,
|
||||
this.Config.GetValue(DmtpConfigExtension.DmtpOptionProperty).Id, timeout, this.Config.GetValue(DmtpConfigExtension.DmtpOptionProperty).Metadata, token);
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.m_semaphore.Release();
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual async Task<ITcpDmtpClient> ConnectAsync(CancellationToken token, int timeout = 5000)
|
||||
{
|
||||
try
|
||||
{
|
||||
await this.m_semaphore.WaitAsync();
|
||||
if (this.IsHandshaked)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
if (!this.Online)
|
||||
{
|
||||
await base.ConnectAsync(timeout).ConfigureFalseAwait();
|
||||
}
|
||||
|
||||
await this.m_dmtpActor.HandshakeAsync(this.Config.GetValue(DmtpConfigExtension.VerifyTokenProperty), this.Config.GetValue(DmtpConfigExtension.DefaultIdProperty), timeout, this.Config.GetValue(DmtpConfigExtension.MetadataProperty), token).ConfigureFalseAwait();
|
||||
return this;
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.m_semaphore.Release();
|
||||
this.m_semaphoreForConnect.Release();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ namespace ThingsGateway.Foundation.Dmtp
|
||||
/// <summary>
|
||||
/// 连接令箭
|
||||
/// </summary>
|
||||
public string VerifyToken => this.Config?.GetValue(DmtpConfigExtension.VerifyTokenProperty);
|
||||
public string VerifyToken => this.Config.GetValue(DmtpConfigExtension.DmtpOptionProperty).VerifyToken;
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void LoadConfig(TouchSocketConfig config)
|
||||
|
||||
@@ -43,18 +43,18 @@ namespace ThingsGateway.Foundation.Dmtp
|
||||
/// <inheritdoc/>
|
||||
public IDmtpActor DmtpActor { get => this.m_dmtpActor; }
|
||||
|
||||
/// <inheritdoc cref="IDmtpActor.IsHandshaked"/>
|
||||
/// <inheritdoc cref="IHandshakeObject.IsHandshaked"/>
|
||||
public bool IsHandshaked => this.DmtpActor != null && this.DmtpActor.IsHandshaked;
|
||||
|
||||
/// <summary>
|
||||
/// 验证超时时间,默认为3000ms
|
||||
/// </summary>
|
||||
public int VerifyTimeout => this.Config.GetValue(DmtpConfigExtension.VerifyTimeoutProperty);
|
||||
public TimeSpan VerifyTimeout => this.Config.GetValue(DmtpConfigExtension.DmtpOptionProperty).VerifyTimeout;
|
||||
|
||||
/// <summary>
|
||||
/// 连接令箭
|
||||
/// </summary>
|
||||
public string VerifyToken => this.Config.GetValue(DmtpConfigExtension.VerifyTokenProperty);
|
||||
public string VerifyToken => this.Config.GetValue(DmtpConfigExtension.DmtpOptionProperty).VerifyToken;
|
||||
|
||||
#region 内部委托绑定
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace ThingsGateway.Foundation.Dmtp
|
||||
/// <summary>
|
||||
/// IWebSocketDmtpClient
|
||||
/// </summary>
|
||||
public interface IWebSocketDmtpClient : IWebSocketDmtpClientBase
|
||||
public interface IWebSocketDmtpClient : IWebSocketDmtpClientBase, ISetupConfigObject
|
||||
{
|
||||
/// <summary>
|
||||
/// 异步连接
|
||||
|
||||
@@ -22,14 +22,5 @@ namespace ThingsGateway.Foundation.Dmtp
|
||||
/// </summary>
|
||||
string Id { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 加载到当前客户端的配置
|
||||
/// </summary>
|
||||
TouchSocketConfig Config { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否已完成<see cref="IDmtpActor.IsHandshaked"/>
|
||||
/// </summary>
|
||||
bool IsHandshaked { get; }
|
||||
}
|
||||
}
|
||||
@@ -29,7 +29,7 @@ namespace ThingsGateway.Foundation.Dmtp
|
||||
/// <summary>
|
||||
/// WebSocketDmtpClient
|
||||
/// </summary>
|
||||
public class WebSocketDmtpClient : BaseSocket, IWebSocketDmtpClient
|
||||
public class WebSocketDmtpClient : SetupConfigObject, IWebSocketDmtpClient
|
||||
{
|
||||
/// <summary>
|
||||
/// WebSocketDmtpClient
|
||||
@@ -66,13 +66,7 @@ namespace ThingsGateway.Foundation.Dmtp
|
||||
/// <inheritdoc/>
|
||||
public bool CanSend => this.m_client.State == WebSocketState.Open;
|
||||
|
||||
/// <summary>
|
||||
/// 客户端配置
|
||||
/// </summary>
|
||||
public TouchSocketConfig Config { get; private set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IContainer Container { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 断开连接
|
||||
@@ -94,20 +88,14 @@ namespace ThingsGateway.Foundation.Dmtp
|
||||
/// <inheritdoc/>
|
||||
public DateTime LastSendTime => this.m_sendCounter.LastIncrement;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IPluginsManager PluginsManager { get; private set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Protocol Protocol { get; set; } = DmtpUtility.DmtpProtocol;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int ReceiveBufferSize => this.m_receiveBufferSize;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IPHost RemoteIPHost { get; private set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int SendBufferSize => this.m_sendBufferSize;
|
||||
|
||||
/// <summary>
|
||||
/// 发送<see cref="IDmtpActor"/>关闭消息。
|
||||
@@ -165,9 +153,9 @@ namespace ThingsGateway.Foundation.Dmtp
|
||||
_ = this.BeginReceive();
|
||||
}
|
||||
|
||||
this.m_dmtpActor.Handshake(this.Config.GetValue(DmtpConfigExtension.VerifyTokenProperty),
|
||||
this.Config.GetValue(DmtpConfigExtension.DefaultIdProperty),
|
||||
timeout, this.Config.GetValue(DmtpConfigExtension.MetadataProperty), token);
|
||||
this.m_dmtpActor.Handshake(this.Config.GetValue(DmtpConfigExtension.DmtpOptionProperty).VerifyToken,
|
||||
this.Config.GetValue(DmtpConfigExtension.DmtpOptionProperty).Id,
|
||||
timeout, this.Config.GetValue(DmtpConfigExtension.DmtpOptionProperty).Metadata, token);
|
||||
this.IsHandshaked = true;
|
||||
}
|
||||
finally
|
||||
@@ -194,28 +182,6 @@ namespace ThingsGateway.Foundation.Dmtp
|
||||
this.DmtpActor.ResetId(newId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 配置
|
||||
/// </summary>
|
||||
/// <param name="config"></param>
|
||||
/// <exception cref="Exception"></exception>
|
||||
public IWebSocketDmtpClient Setup(TouchSocketConfig config)
|
||||
{
|
||||
if (config == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(config));
|
||||
}
|
||||
|
||||
this.ThrowIfDisposed();
|
||||
|
||||
this.BuildConfig(config);
|
||||
|
||||
this.PluginsManager.Raise(nameof(ILoadingConfigPlugin.OnLoadingConfig), this, new ConfigEventArgs(config));
|
||||
this.LoadConfig(this.Config);
|
||||
this.PluginsManager.Raise(nameof(ILoadedConfigPlugin.OnLoadedConfig), this, new ConfigEventArgs(config));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Dispose(bool disposing)
|
||||
@@ -236,11 +202,9 @@ namespace ThingsGateway.Foundation.Dmtp
|
||||
/// 加载配置
|
||||
/// </summary>
|
||||
/// <param name="config"></param>
|
||||
protected virtual void LoadConfig(TouchSocketConfig config)
|
||||
protected override void LoadConfig(TouchSocketConfig config)
|
||||
{
|
||||
this.RemoteIPHost = config.GetValue(TouchSocketConfigExtension.RemoteIPHostProperty);
|
||||
this.Logger ??= this.Container.Resolve<ILog>();
|
||||
|
||||
if (this.Container.IsRegistered(typeof(IDmtpRouteService)))
|
||||
{
|
||||
this.m_findDmtpActor = this.Container.Resolve<IDmtpRouteService>().FindDmtpActor;
|
||||
@@ -266,7 +230,7 @@ namespace ThingsGateway.Foundation.Dmtp
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
using (var byteBlock = new ByteBlock(this.ReceiveBufferSize))
|
||||
using (var byteBlock = new ByteBlock(this.m_receiveBufferSize))
|
||||
{
|
||||
var result = await this.m_client.ReceiveAsync(new ArraySegment<byte>(byteBlock.Buffer, 0, byteBlock.Capacity), default);
|
||||
if (result.Count == 0)
|
||||
@@ -290,7 +254,7 @@ namespace ThingsGateway.Foundation.Dmtp
|
||||
|
||||
private void BreakOut(string msg, bool manual)
|
||||
{
|
||||
lock (this.SyncRoot)
|
||||
lock (this.m_semaphoreForConnect)
|
||||
{
|
||||
if (this.IsHandshaked)
|
||||
{
|
||||
@@ -304,47 +268,6 @@ namespace ThingsGateway.Foundation.Dmtp
|
||||
}
|
||||
}
|
||||
|
||||
private void BuildConfig(TouchSocketConfig config)
|
||||
{
|
||||
this.Config = config;
|
||||
|
||||
if (!(config.GetValue(TouchSocketCoreConfigExtension.ContainerProperty) is IContainer container))
|
||||
{
|
||||
container = new Container();
|
||||
}
|
||||
|
||||
if (!container.IsRegistered(typeof(ILog)))
|
||||
{
|
||||
container.RegisterSingleton<ILog, LoggerGroup>();
|
||||
}
|
||||
|
||||
if (!(config.GetValue(TouchSocketCoreConfigExtension.PluginsManagerProperty) is IPluginsManager pluginsManager))
|
||||
{
|
||||
pluginsManager = new PluginsManager(container);
|
||||
}
|
||||
|
||||
if (container.IsRegistered(typeof(IPluginsManager)))
|
||||
{
|
||||
pluginsManager = container.Resolve<IPluginsManager>();
|
||||
}
|
||||
else
|
||||
{
|
||||
container.RegisterSingleton<IPluginsManager>(pluginsManager);
|
||||
}
|
||||
|
||||
if (config.GetValue(TouchSocketCoreConfigExtension.ConfigureContainerProperty) is Action<IContainer> actionContainer)
|
||||
{
|
||||
actionContainer.Invoke(container);
|
||||
}
|
||||
|
||||
if (config.GetValue(TouchSocketCoreConfigExtension.ConfigurePluginsProperty) is Action<IPluginsManager> actionPluginsManager)
|
||||
{
|
||||
pluginsManager.Enable = true;
|
||||
actionPluginsManager.Invoke(pluginsManager);
|
||||
}
|
||||
this.Container = container;
|
||||
this.PluginsManager = pluginsManager;
|
||||
}
|
||||
|
||||
private void OnReceivePeriod(long value)
|
||||
{
|
||||
@@ -366,7 +289,7 @@ namespace ThingsGateway.Foundation.Dmtp
|
||||
var message = (DmtpMessage)requestInfo;
|
||||
if (!this.m_dmtpActor.InputReceivedData(message).GetFalseAwaitResult())
|
||||
{
|
||||
this.PluginsManager.Raise(nameof(IDmtpReceivedPlugin.OnDmtpReceived), this, new DmtpMessageEventArgs(message));
|
||||
this.PluginsManager?.Raise(nameof(IDmtpReceivedPlugin.OnDmtpReceived), this, new DmtpMessageEventArgs(message));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,9 +10,6 @@
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
|
||||
namespace ThingsGateway.Foundation.Dmtp
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -18,77 +18,20 @@ namespace ThingsGateway.Foundation.Dmtp
|
||||
public static class DmtpConfigExtension
|
||||
{
|
||||
/// <summary>
|
||||
/// 默认使用Id。
|
||||
/// 设置Dmtp相关配置。
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty<string> DefaultIdProperty =
|
||||
DependencyProperty<string>.Register("DefaultId", null);
|
||||
public static readonly DependencyProperty<DmtpOption> DmtpOptionProperty =
|
||||
DependencyProperty<DmtpOption>.Register("DmtpOption", new DmtpOption());
|
||||
|
||||
/// <summary>
|
||||
/// DmtpClient连接时的元数据, 所需类型<see cref="Metadata"/>
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty<Metadata> MetadataProperty = DependencyProperty<Metadata>.Register("Metadata", null);
|
||||
|
||||
/// <summary>
|
||||
/// 验证超时时间,默认为3000ms, 所需类型<see cref="int"/>
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty<int> VerifyTimeoutProperty =
|
||||
DependencyProperty<int>.Register("VerifyTimeout", 3000);
|
||||
|
||||
/// <summary>
|
||||
/// 连接令箭,当为null或空时,重置为默认值“rrqm”, 所需类型<see cref="string"/>
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty<string> VerifyTokenProperty =
|
||||
DependencyProperty<string>.Register("VerifyToken", "rrqm");
|
||||
|
||||
/// <summary>
|
||||
/// 设置默认的使用Id。仅在DmtpRpc组件适用。
|
||||
/// <para>
|
||||
/// 使用该功能时,仅在服务器的Handshaking之后生效。且如果id重复,则会连接失败。
|
||||
/// </para>
|
||||
/// 设置Dmtp相关配置。
|
||||
/// </summary>
|
||||
/// <param name="config"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static TouchSocketConfig SetDefaultId(this TouchSocketConfig config, string value)
|
||||
public static TouchSocketConfig SetDmtpOption(this TouchSocketConfig config, DmtpOption value)
|
||||
{
|
||||
config.SetValue(DefaultIdProperty, value);
|
||||
return config;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置DmtpClient连接时的元数据
|
||||
/// <para>仅适用于DmtpClient系类</para>
|
||||
/// </summary>
|
||||
/// <param name="config"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static TouchSocketConfig SetMetadata(this TouchSocketConfig config, Metadata value)
|
||||
{
|
||||
config.SetValue(MetadataProperty, value);
|
||||
return config;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 验证超时时间,默认为3000ms.
|
||||
/// </summary>
|
||||
/// <param name="config"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static TouchSocketConfig SetVerifyTimeout(this TouchSocketConfig config, int value)
|
||||
{
|
||||
config.SetValue(VerifyTimeoutProperty, value);
|
||||
return config;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 连接令箭,当为null或空时,重置为默认值“rrqm”
|
||||
/// </summary>
|
||||
/// <param name="config"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static TouchSocketConfig SetVerifyToken(this TouchSocketConfig config, string value)
|
||||
{
|
||||
config.SetValue(VerifyTokenProperty, value);
|
||||
config.SetValue(DmtpOptionProperty, value);
|
||||
return config;
|
||||
}
|
||||
|
||||
@@ -183,32 +126,6 @@ namespace ThingsGateway.Foundation.Dmtp
|
||||
|
||||
#endregion 创建HttpDmtp
|
||||
|
||||
//#region 创建UdpTouchRpc
|
||||
|
||||
///// <summary>
|
||||
///// 构建UdpTouchRpc类
|
||||
///// </summary>
|
||||
///// <typeparam name="TClient"></typeparam>
|
||||
///// <param name="config"></param>
|
||||
///// <returns></returns>
|
||||
//public static TClient BuildWithUdpTouchRpc<TClient>(this TouchSocketConfig config) where TClient : IUdpTouchRpc
|
||||
//{
|
||||
// TClient client = Activator.CreateInstance<TClient>();
|
||||
// client.Setup(config);
|
||||
// client.Start();
|
||||
// return client;
|
||||
//}
|
||||
|
||||
///// <summary>
|
||||
///// 构建UdpTouchRpc类客户端
|
||||
///// </summary>
|
||||
///// <param name="config"></param>
|
||||
///// <returns></returns>
|
||||
//public static UdpTouchRpc BuildWithUdpTouchRpc(this TouchSocketConfig config)
|
||||
//{
|
||||
// return BuildWithUdpTouchRpc<UdpTouchRpc>(config);
|
||||
//}
|
||||
|
||||
//#endregion 创建UdpTouchRpc
|
||||
}
|
||||
}
|
||||
@@ -77,7 +77,7 @@ namespace ThingsGateway.Foundation.Dmtp.FileTransfer
|
||||
{
|
||||
if (await this.DmtpActor.TryFindDmtpActor(waitFileResource.TargetId) is DmtpActor actor)
|
||||
{
|
||||
await actor.SendAsync(this.m_pullFileResourceInfo_Request, byteBlock);
|
||||
actor.Send(this.m_pullFileResourceInfo_Request, byteBlock);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
@@ -92,12 +92,12 @@ namespace ThingsGateway.Foundation.Dmtp.FileTransfer
|
||||
waitFileResource.SwitchId();
|
||||
byteBlock.Reset();
|
||||
waitFileResource.Package(byteBlock);
|
||||
await this.DmtpActor.SendAsync(this.m_pullFileResourceInfo_Response, byteBlock);
|
||||
this.DmtpActor.Send(this.m_pullFileResourceInfo_Response, byteBlock);
|
||||
}
|
||||
else
|
||||
{
|
||||
waitFileResource.UnpackageBody(byteBlock);
|
||||
_ = this.RequestPullFileResourceInfo(waitFileResource);
|
||||
_ = Task.Factory.StartNew(this.RequestPullFileResourceInfo, waitFileResource);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -116,7 +116,7 @@ namespace ThingsGateway.Foundation.Dmtp.FileTransfer
|
||||
{
|
||||
if (await this.DmtpActor.TryFindDmtpActor(waitFileResource.TargetId) is DmtpActor actor)
|
||||
{
|
||||
await actor.SendAsync(this.m_pullFileResourceInfo_Response, byteBlock);
|
||||
actor.Send(this.m_pullFileResourceInfo_Response, byteBlock);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -406,7 +406,7 @@ namespace ThingsGateway.Foundation.Dmtp.FileTransfer
|
||||
else
|
||||
{
|
||||
waitSmallFilePackage.UnpackageBody(byteBlock);
|
||||
_ = this.RequestPullSmallFile(waitSmallFilePackage);
|
||||
_ = Task.Factory.StartNew(this.RequestPullSmallFile, waitSmallFilePackage);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -1324,7 +1324,7 @@ namespace ThingsGateway.Foundation.Dmtp.FileTransfer
|
||||
{
|
||||
waitFileResource.SwitchId();
|
||||
waitFileResource.Package(byteBlock);
|
||||
await this.DmtpActor.SendAsync(this.m_pullFileResourceInfo_Response, byteBlock);
|
||||
this.DmtpActor.Send(this.m_pullFileResourceInfo_Response, byteBlock);
|
||||
}
|
||||
}
|
||||
catch
|
||||
|
||||
@@ -59,12 +59,7 @@ namespace ThingsGateway.Foundation.Dmtp.FileTransfer
|
||||
/// </summary>
|
||||
public int TryCount { get; set; } = 10;
|
||||
|
||||
/// <summary>
|
||||
/// 设置结果状态
|
||||
/// </summary>
|
||||
/// <param name="result"></param>
|
||||
/// <returns></returns>
|
||||
public Result SetResult(Result result)
|
||||
internal Result SetResult(Result result)
|
||||
{
|
||||
this.Result = result;
|
||||
return result;
|
||||
|
||||
@@ -240,7 +240,7 @@ namespace ThingsGateway.Foundation.Dmtp.Rpc
|
||||
DmtpRpcPackage = rpcPackage
|
||||
};
|
||||
this.TryAdd(rpcPackage.Sign, callContext);
|
||||
if (methodInstance.MethodFlags.HasFlag(MethodFlags.IncludeCallContext))
|
||||
if (methodInstance.IncludeCallContext)
|
||||
{
|
||||
ps = new object[methodInstance.ParameterTypes.Length];
|
||||
ps[0] = callContext;
|
||||
@@ -314,7 +314,7 @@ namespace ThingsGateway.Foundation.Dmtp.Rpc
|
||||
rpcPackage.ParametersBytes = new List<byte[]>();
|
||||
|
||||
var i = 0;
|
||||
if (methodInstance.MethodFlags.HasFlag(MethodFlags.IncludeCallContext))
|
||||
if (methodInstance.IncludeCallContext)
|
||||
{
|
||||
i = 1;
|
||||
}
|
||||
@@ -383,6 +383,23 @@ namespace ThingsGateway.Foundation.Dmtp.Rpc
|
||||
return default;
|
||||
}
|
||||
|
||||
private static void CheckWaitDataStatus(WaitDataStatus status)
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
return;
|
||||
case WaitDataStatus.Canceled: throw new OperationCanceledException();
|
||||
case WaitDataStatus.Overtime: throw new TimeoutException();
|
||||
case WaitDataStatus.Disposed:
|
||||
case WaitDataStatus.Default:
|
||||
default:
|
||||
{
|
||||
throw new Exception(TouchSocketCoreResource.UnknownError.GetDescription());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region Rpc
|
||||
|
||||
/// <inheritdoc/>
|
||||
@@ -429,53 +446,33 @@ namespace ThingsGateway.Foundation.Dmtp.Rpc
|
||||
}
|
||||
case FeedbackType.WaitSend:
|
||||
{
|
||||
switch (waitData.Wait(invokeOption.Timeout))
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case WaitDataStatus.Overtime:
|
||||
{
|
||||
throw new TimeoutException("等待结果超时");
|
||||
}
|
||||
}
|
||||
CheckWaitDataStatus(waitData.Wait(invokeOption.Timeout));
|
||||
return returnType.GetDefault();
|
||||
}
|
||||
case FeedbackType.WaitInvoke:
|
||||
{
|
||||
switch (waitData.Wait(invokeOption.Timeout))
|
||||
CheckWaitDataStatus(waitData.Wait(invokeOption.Timeout));
|
||||
var resultContext = (DmtpRpcPackage)waitData.WaitResult;
|
||||
resultContext.ThrowStatus();
|
||||
if (resultContext.IsByRef)
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
try
|
||||
{
|
||||
for (var i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
var resultContext = (DmtpRpcPackage)waitData.WaitResult;
|
||||
resultContext.ThrowStatus();
|
||||
if (resultContext.IsByRef)
|
||||
{
|
||||
try
|
||||
{
|
||||
for (var i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
parameters[i] = this.SerializationSelector.DeserializeParameter(resultContext.SerializationType, resultContext.ParametersBytes[i], types[i]);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new Exception(e.Message);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
parameters = null;
|
||||
}
|
||||
return this.SerializationSelector.DeserializeParameter(resultContext.SerializationType, resultContext.ReturnParameterBytes, returnType);
|
||||
}
|
||||
case WaitDataStatus.Overtime:
|
||||
{
|
||||
throw new TimeoutException("等待结果超时");
|
||||
parameters[i] = this.SerializationSelector.DeserializeParameter(resultContext.SerializationType, resultContext.ParametersBytes[i], types[i]);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new Exception(e.Message);
|
||||
}
|
||||
}
|
||||
return returnType.GetDefault();
|
||||
else
|
||||
{
|
||||
parameters = null;
|
||||
}
|
||||
return this.SerializationSelector.DeserializeParameter(resultContext.SerializationType, resultContext.ReturnParameterBytes, returnType);
|
||||
}
|
||||
default:
|
||||
return returnType.GetDefault();
|
||||
@@ -531,44 +528,24 @@ namespace ThingsGateway.Foundation.Dmtp.Rpc
|
||||
|
||||
case FeedbackType.WaitSend:
|
||||
{
|
||||
switch (waitData.Wait(invokeOption.Timeout))
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case WaitDataStatus.Overtime:
|
||||
{
|
||||
throw new TimeoutException("等待结果超时");
|
||||
}
|
||||
}
|
||||
CheckWaitDataStatus(waitData.Wait(invokeOption.Timeout));
|
||||
break;
|
||||
}
|
||||
case FeedbackType.WaitInvoke:
|
||||
{
|
||||
switch (waitData.Wait(invokeOption.Timeout))
|
||||
CheckWaitDataStatus(waitData.Wait(invokeOption.Timeout));
|
||||
var resultContext = (DmtpRpcPackage)waitData.WaitResult;
|
||||
resultContext.ThrowStatus();
|
||||
if (resultContext.IsByRef)
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
{
|
||||
var resultContext = (DmtpRpcPackage)waitData.WaitResult;
|
||||
resultContext.ThrowStatus();
|
||||
if (resultContext.IsByRef)
|
||||
{
|
||||
for (var i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
parameters[i] = this.SerializationSelector.DeserializeParameter(resultContext.SerializationType, resultContext.ParametersBytes[i], types[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
parameters = null;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WaitDataStatus.Overtime:
|
||||
{
|
||||
throw new TimeoutException("等待结果超时");
|
||||
}
|
||||
for (var i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
parameters[i] = this.SerializationSelector.DeserializeParameter(resultContext.SerializationType, resultContext.ParametersBytes[i], types[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
parameters = null;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -630,33 +607,14 @@ namespace ThingsGateway.Foundation.Dmtp.Rpc
|
||||
|
||||
case FeedbackType.WaitSend:
|
||||
{
|
||||
switch (waitData.Wait(invokeOption.Timeout))
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
break;
|
||||
|
||||
case WaitDataStatus.Overtime:
|
||||
{
|
||||
throw new TimeoutException("等待结果超时");
|
||||
}
|
||||
}
|
||||
CheckWaitDataStatus(waitData.Wait(invokeOption.Timeout));
|
||||
break;
|
||||
}
|
||||
case FeedbackType.WaitInvoke:
|
||||
{
|
||||
switch (waitData.Wait(invokeOption.Timeout))
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
{
|
||||
var resultContext = (DmtpRpcPackage)waitData.WaitResult;
|
||||
resultContext.ThrowStatus();
|
||||
break;
|
||||
}
|
||||
case WaitDataStatus.Overtime:
|
||||
{
|
||||
throw new TimeoutException("等待结果超时");
|
||||
}
|
||||
}
|
||||
CheckWaitDataStatus(waitData.Wait(invokeOption.Timeout));
|
||||
var resultContext = (DmtpRpcPackage)waitData.WaitResult;
|
||||
resultContext.ThrowStatus();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -719,31 +677,15 @@ namespace ThingsGateway.Foundation.Dmtp.Rpc
|
||||
}
|
||||
case FeedbackType.WaitSend:
|
||||
{
|
||||
switch (waitData.Wait(invokeOption.Timeout))
|
||||
{
|
||||
case WaitDataStatus.Overtime:
|
||||
{
|
||||
throw new TimeoutException("等待结果超时");
|
||||
}
|
||||
}
|
||||
CheckWaitDataStatus(waitData.Wait(invokeOption.Timeout));
|
||||
return returnType.GetDefault();
|
||||
}
|
||||
case FeedbackType.WaitInvoke:
|
||||
{
|
||||
switch (waitData.Wait(invokeOption.Timeout))
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
{
|
||||
var resultContext = (DmtpRpcPackage)waitData.WaitResult;
|
||||
resultContext.ThrowStatus();
|
||||
return this.SerializationSelector.DeserializeParameter(resultContext.SerializationType, resultContext.ReturnParameterBytes, returnType);
|
||||
}
|
||||
case WaitDataStatus.Overtime:
|
||||
{
|
||||
throw new TimeoutException("等待结果超时");
|
||||
}
|
||||
}
|
||||
return returnType.GetDefault();
|
||||
CheckWaitDataStatus(waitData.Wait(invokeOption.Timeout));
|
||||
var resultContext = (DmtpRpcPackage)waitData.WaitResult;
|
||||
resultContext.ThrowStatus();
|
||||
return this.SerializationSelector.DeserializeParameter(resultContext.SerializationType, resultContext.ReturnParameterBytes, returnType);
|
||||
}
|
||||
|
||||
default:
|
||||
@@ -794,7 +736,7 @@ namespace ThingsGateway.Foundation.Dmtp.Rpc
|
||||
}
|
||||
|
||||
rpcPackage.Package(byteBlock);
|
||||
this.DmtpActor.Send(this.m_invoke_Request, byteBlock.Buffer, 0, byteBlock.Len);
|
||||
await this.DmtpActor.SendAsync(this.m_invoke_Request, byteBlock.Buffer, 0, byteBlock.Len);
|
||||
}
|
||||
|
||||
switch (invokeOption.FeedbackType)
|
||||
@@ -804,33 +746,14 @@ namespace ThingsGateway.Foundation.Dmtp.Rpc
|
||||
|
||||
case FeedbackType.WaitSend:
|
||||
{
|
||||
switch (await waitData.WaitAsync(invokeOption.Timeout).ConfigureFalseAwait())
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
break;
|
||||
|
||||
case WaitDataStatus.Overtime:
|
||||
{
|
||||
throw new TimeoutException("等待结果超时");
|
||||
}
|
||||
}
|
||||
CheckWaitDataStatus(await waitData.WaitAsync(invokeOption.Timeout).ConfigureFalseAwait());
|
||||
break;
|
||||
}
|
||||
case FeedbackType.WaitInvoke:
|
||||
{
|
||||
switch (await waitData.WaitAsync(invokeOption.Timeout).ConfigureFalseAwait())
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
{
|
||||
var resultContext = (DmtpRpcPackage)waitData.WaitResult;
|
||||
resultContext.ThrowStatus();
|
||||
break;
|
||||
}
|
||||
case WaitDataStatus.Overtime:
|
||||
{
|
||||
throw new TimeoutException("等待结果超时");
|
||||
}
|
||||
}
|
||||
CheckWaitDataStatus(await waitData.WaitAsync(invokeOption.Timeout).ConfigureFalseAwait());
|
||||
var resultContext = (DmtpRpcPackage)waitData.WaitResult;
|
||||
resultContext.ThrowStatus();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -881,7 +804,7 @@ namespace ThingsGateway.Foundation.Dmtp.Rpc
|
||||
|
||||
rpcPackage.Package(byteBlock);
|
||||
|
||||
this.DmtpActor.Send(this.m_invoke_Request, byteBlock.Buffer, 0, byteBlock.Len);
|
||||
await this.DmtpActor.SendAsync(this.m_invoke_Request, byteBlock.Buffer, 0, byteBlock.Len);
|
||||
}
|
||||
|
||||
switch (invokeOption.FeedbackType)
|
||||
@@ -892,31 +815,15 @@ namespace ThingsGateway.Foundation.Dmtp.Rpc
|
||||
}
|
||||
case FeedbackType.WaitSend:
|
||||
{
|
||||
switch (await waitData.WaitAsync(invokeOption.Timeout).ConfigureFalseAwait())
|
||||
{
|
||||
case WaitDataStatus.Overtime:
|
||||
{
|
||||
throw new TimeoutException("等待结果超时");
|
||||
}
|
||||
}
|
||||
CheckWaitDataStatus(await waitData.WaitAsync(invokeOption.Timeout).ConfigureFalseAwait());
|
||||
return returnType.GetDefault();
|
||||
}
|
||||
case FeedbackType.WaitInvoke:
|
||||
{
|
||||
switch (await waitData.WaitAsync(invokeOption.Timeout).ConfigureFalseAwait())
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
{
|
||||
var resultContext = (DmtpRpcPackage)waitData.WaitResult;
|
||||
resultContext.ThrowStatus();
|
||||
return this.SerializationSelector.DeserializeParameter(resultContext.SerializationType, resultContext.ReturnParameterBytes, returnType);
|
||||
}
|
||||
case WaitDataStatus.Overtime:
|
||||
{
|
||||
throw new TimeoutException("等待结果超时");
|
||||
}
|
||||
}
|
||||
return returnType.GetDefault();
|
||||
CheckWaitDataStatus(await waitData.WaitAsync(invokeOption.Timeout).ConfigureFalseAwait());
|
||||
var resultContext = (DmtpRpcPackage)waitData.WaitResult;
|
||||
resultContext.ThrowStatus();
|
||||
return this.SerializationSelector.DeserializeParameter(resultContext.SerializationType, resultContext.ReturnParameterBytes, returnType);
|
||||
}
|
||||
|
||||
default:
|
||||
@@ -1000,33 +907,14 @@ namespace ThingsGateway.Foundation.Dmtp.Rpc
|
||||
|
||||
case FeedbackType.WaitSend:
|
||||
{
|
||||
switch (waitData.Wait(invokeOption.Timeout))
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
break;
|
||||
|
||||
case WaitDataStatus.Overtime:
|
||||
{
|
||||
throw new TimeoutException("等待结果超时");
|
||||
}
|
||||
}
|
||||
CheckWaitDataStatus(waitData.Wait(invokeOption.Timeout));
|
||||
break;
|
||||
}
|
||||
case FeedbackType.WaitInvoke:
|
||||
{
|
||||
switch (waitData.Wait(invokeOption.Timeout))
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
{
|
||||
var resultContext = (DmtpRpcPackage)waitData.WaitResult;
|
||||
resultContext.ThrowStatus();
|
||||
break;
|
||||
}
|
||||
case WaitDataStatus.Overtime:
|
||||
{
|
||||
throw new TimeoutException("等待结果超时");
|
||||
}
|
||||
}
|
||||
CheckWaitDataStatus(waitData.Wait(invokeOption.Timeout));
|
||||
var resultContext = (DmtpRpcPackage)waitData.WaitResult;
|
||||
resultContext.ThrowStatus();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -1105,31 +993,15 @@ namespace ThingsGateway.Foundation.Dmtp.Rpc
|
||||
}
|
||||
case FeedbackType.WaitSend:
|
||||
{
|
||||
switch (waitData.Wait(invokeOption.Timeout))
|
||||
{
|
||||
case WaitDataStatus.Overtime:
|
||||
{
|
||||
throw new TimeoutException("等待结果超时");
|
||||
}
|
||||
}
|
||||
CheckWaitDataStatus(waitData.Wait(invokeOption.Timeout));
|
||||
return returnType.GetDefault();
|
||||
}
|
||||
case FeedbackType.WaitInvoke:
|
||||
{
|
||||
switch (waitData.Wait(invokeOption.Timeout))
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
{
|
||||
var resultContext = (DmtpRpcPackage)waitData.WaitResult;
|
||||
resultContext.ThrowStatus();
|
||||
return this.SerializationSelector.DeserializeParameter(resultContext.SerializationType, resultContext.ReturnParameterBytes, returnType);
|
||||
}
|
||||
case WaitDataStatus.Overtime:
|
||||
{
|
||||
throw new TimeoutException("等待结果超时");
|
||||
}
|
||||
}
|
||||
return returnType.GetDefault();
|
||||
CheckWaitDataStatus(waitData.Wait(invokeOption.Timeout));
|
||||
var resultContext = (DmtpRpcPackage)waitData.WaitResult;
|
||||
resultContext.ThrowStatus();
|
||||
return this.SerializationSelector.DeserializeParameter(resultContext.SerializationType, resultContext.ReturnParameterBytes, returnType);
|
||||
}
|
||||
|
||||
default:
|
||||
@@ -1206,40 +1078,24 @@ namespace ThingsGateway.Foundation.Dmtp.Rpc
|
||||
}
|
||||
case FeedbackType.WaitSend:
|
||||
{
|
||||
switch (waitData.Wait(invokeOption.Timeout))
|
||||
{
|
||||
case WaitDataStatus.Overtime:
|
||||
{
|
||||
throw new TimeoutException("等待结果超时");
|
||||
}
|
||||
}
|
||||
CheckWaitDataStatus(waitData.Wait(invokeOption.Timeout));
|
||||
return;
|
||||
}
|
||||
case FeedbackType.WaitInvoke:
|
||||
{
|
||||
switch (waitData.Wait(invokeOption.Timeout))
|
||||
CheckWaitDataStatus(waitData.Wait(invokeOption.Timeout));
|
||||
var resultContext = (DmtpRpcPackage)waitData.WaitResult;
|
||||
resultContext.ThrowStatus();
|
||||
if (resultContext.IsByRef)
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
{
|
||||
var resultContext = (DmtpRpcPackage)waitData.WaitResult;
|
||||
resultContext.ThrowStatus();
|
||||
if (resultContext.IsByRef)
|
||||
{
|
||||
for (var i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
parameters[i] = this.SerializationSelector.DeserializeParameter(resultContext.SerializationType, resultContext.ParametersBytes[i], types[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
parameters = null;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WaitDataStatus.Overtime:
|
||||
{
|
||||
throw new TimeoutException("等待结果超时");
|
||||
}
|
||||
for (var i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
parameters[i] = this.SerializationSelector.DeserializeParameter(resultContext.SerializationType, resultContext.ParametersBytes[i], types[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
parameters = null;
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -1315,42 +1171,26 @@ namespace ThingsGateway.Foundation.Dmtp.Rpc
|
||||
}
|
||||
case FeedbackType.WaitSend:
|
||||
{
|
||||
switch (waitData.Wait(invokeOption.Timeout))
|
||||
{
|
||||
case WaitDataStatus.Overtime:
|
||||
{
|
||||
throw new TimeoutException("等待结果超时");
|
||||
}
|
||||
}
|
||||
CheckWaitDataStatus(waitData.Wait(invokeOption.Timeout));
|
||||
return returnType.GetDefault();
|
||||
}
|
||||
case FeedbackType.WaitInvoke:
|
||||
{
|
||||
switch (waitData.Wait(invokeOption.Timeout))
|
||||
CheckWaitDataStatus(waitData.Wait(invokeOption.Timeout));
|
||||
var resultContext = (DmtpRpcPackage)waitData.WaitResult;
|
||||
resultContext.ThrowStatus();
|
||||
if (resultContext.IsByRef)
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
{
|
||||
var resultContext = (DmtpRpcPackage)waitData.WaitResult;
|
||||
resultContext.ThrowStatus();
|
||||
if (resultContext.IsByRef)
|
||||
{
|
||||
for (var i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
parameters[i] = this.SerializationSelector.DeserializeParameter(resultContext.SerializationType, resultContext.ParametersBytes[i], types[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
parameters = null;
|
||||
}
|
||||
return this.SerializationSelector.DeserializeParameter(resultContext.SerializationType, resultContext.ReturnParameterBytes, returnType);
|
||||
}
|
||||
case WaitDataStatus.Overtime:
|
||||
{
|
||||
throw new TimeoutException("等待结果超时");
|
||||
}
|
||||
for (var i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
parameters[i] = this.SerializationSelector.DeserializeParameter(resultContext.SerializationType, resultContext.ParametersBytes[i], types[i]);
|
||||
}
|
||||
}
|
||||
return returnType.GetDefault();
|
||||
else
|
||||
{
|
||||
parameters = null;
|
||||
}
|
||||
return this.SerializationSelector.DeserializeParameter(resultContext.SerializationType, resultContext.ReturnParameterBytes, returnType);
|
||||
}
|
||||
|
||||
default:
|
||||
@@ -1420,7 +1260,7 @@ namespace ThingsGateway.Foundation.Dmtp.Rpc
|
||||
|
||||
rpcPackage.Package(byteBlock);
|
||||
|
||||
this.DmtpActor.Send(this.m_invoke_Request, byteBlock.Buffer, 0, byteBlock.Len);
|
||||
await this.DmtpActor.SendAsync(this.m_invoke_Request, byteBlock.Buffer, 0, byteBlock.Len);
|
||||
}
|
||||
|
||||
switch (invokeOption.FeedbackType)
|
||||
@@ -1430,33 +1270,14 @@ namespace ThingsGateway.Foundation.Dmtp.Rpc
|
||||
|
||||
case FeedbackType.WaitSend:
|
||||
{
|
||||
switch (await waitData.WaitAsync(invokeOption.Timeout).ConfigureFalseAwait())
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
break;
|
||||
|
||||
case WaitDataStatus.Overtime:
|
||||
{
|
||||
throw new TimeoutException("等待结果超时");
|
||||
}
|
||||
}
|
||||
CheckWaitDataStatus(await waitData.WaitAsync(invokeOption.Timeout).ConfigureFalseAwait());
|
||||
break;
|
||||
}
|
||||
case FeedbackType.WaitInvoke:
|
||||
{
|
||||
switch (await waitData.WaitAsync(invokeOption.Timeout).ConfigureFalseAwait())
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
{
|
||||
var resultContext = (DmtpRpcPackage)waitData.WaitResult;
|
||||
resultContext.ThrowStatus();
|
||||
break;
|
||||
}
|
||||
case WaitDataStatus.Overtime:
|
||||
{
|
||||
throw new TimeoutException("等待结果超时");
|
||||
}
|
||||
}
|
||||
CheckWaitDataStatus(await waitData.WaitAsync(invokeOption.Timeout).ConfigureFalseAwait());
|
||||
var resultContext = (DmtpRpcPackage)waitData.WaitResult;
|
||||
resultContext.ThrowStatus();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -1524,7 +1345,7 @@ namespace ThingsGateway.Foundation.Dmtp.Rpc
|
||||
|
||||
rpcPackage.Package(byteBlock);
|
||||
|
||||
this.DmtpActor.Send(this.m_invoke_Request, byteBlock.Buffer, 0, byteBlock.Len);
|
||||
await this.DmtpActor.SendAsync(this.m_invoke_Request, byteBlock.Buffer, 0, byteBlock.Len);
|
||||
}
|
||||
|
||||
switch (invokeOption.FeedbackType)
|
||||
@@ -1535,31 +1356,15 @@ namespace ThingsGateway.Foundation.Dmtp.Rpc
|
||||
}
|
||||
case FeedbackType.WaitSend:
|
||||
{
|
||||
switch (await waitData.WaitAsync(invokeOption.Timeout).ConfigureFalseAwait())
|
||||
{
|
||||
case WaitDataStatus.Overtime:
|
||||
{
|
||||
throw new TimeoutException("等待结果超时");
|
||||
}
|
||||
}
|
||||
CheckWaitDataStatus(await waitData.WaitAsync(invokeOption.Timeout).ConfigureFalseAwait());
|
||||
return returnType.GetDefault();
|
||||
}
|
||||
case FeedbackType.WaitInvoke:
|
||||
{
|
||||
switch (await waitData.WaitAsync(invokeOption.Timeout).ConfigureFalseAwait())
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
{
|
||||
var resultContext = (DmtpRpcPackage)waitData.WaitResult;
|
||||
resultContext.ThrowStatus();
|
||||
return this.SerializationSelector.DeserializeParameter(resultContext.SerializationType, resultContext.ReturnParameterBytes, returnType);
|
||||
}
|
||||
case WaitDataStatus.Overtime:
|
||||
{
|
||||
throw new TimeoutException("等待结果超时");
|
||||
}
|
||||
}
|
||||
return returnType.GetDefault();
|
||||
CheckWaitDataStatus(await waitData.WaitAsync(invokeOption.Timeout).ConfigureFalseAwait());
|
||||
var resultContext = (DmtpRpcPackage)waitData.WaitResult;
|
||||
resultContext.ThrowStatus();
|
||||
return this.SerializationSelector.DeserializeParameter(resultContext.SerializationType, resultContext.ReturnParameterBytes, returnType);
|
||||
}
|
||||
|
||||
default:
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System.Text;
|
||||
using System.Web;
|
||||
|
||||
|
||||
@@ -134,12 +134,12 @@ namespace ThingsGateway.Foundation.Http
|
||||
/// <summary>
|
||||
/// 相对路径(不含参数)
|
||||
/// </summary>
|
||||
public string RelativeURL { get; private set; }
|
||||
public string RelativeURL { get; private set; } = "/";
|
||||
|
||||
/// <summary>
|
||||
/// Url全地址,包含参数
|
||||
/// </summary>
|
||||
public string URL { get; private set; }
|
||||
public string URL { get; private set; } = "/";
|
||||
|
||||
/// <summary>
|
||||
/// 构建响应数据。
|
||||
@@ -175,28 +175,26 @@ namespace ThingsGateway.Foundation.Http
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置Url,必须以“/”开头,可带参数
|
||||
/// 设置Url,可带参数
|
||||
/// </summary>
|
||||
/// <param name="url"></param>
|
||||
/// <param name="justValue"></param>
|
||||
/// <returns></returns>
|
||||
public HttpRequest SetUrl(string url, bool justValue = false)
|
||||
public HttpRequest SetUrl(string url)
|
||||
{
|
||||
this.URL = justValue || url.StartsWith("/") ? url : "/" + url;
|
||||
this.URL = url.StartsWith("/") ? url : $"/{url}";
|
||||
this.ParseUrl();
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 输出
|
||||
/// 设置代理Host
|
||||
/// </summary>
|
||||
public override string ToString()
|
||||
/// <param name="host"></param>
|
||||
/// <returns></returns>
|
||||
public HttpRequest SetProxyHost(string host)
|
||||
{
|
||||
using (var byteBlock = new ByteBlock())
|
||||
{
|
||||
this.Build(byteBlock);
|
||||
return byteBlock.ToString();
|
||||
}
|
||||
this.URL = host;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -412,7 +410,17 @@ namespace ThingsGateway.Foundation.Http
|
||||
}
|
||||
if (urls.Length > 1)
|
||||
{
|
||||
this.m_query = GetParameters(urls[1]);
|
||||
if (this.m_query == null)
|
||||
{
|
||||
this.m_query = GetParameters(urls[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var item in GetParameters(urls[1]))
|
||||
{
|
||||
this.m_query.Add(item.Key, item.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -420,5 +428,17 @@ namespace ThingsGateway.Foundation.Http
|
||||
this.RelativeURL = this.URL;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 输出
|
||||
/// </summary>
|
||||
public override string ToString()
|
||||
{
|
||||
using (var byteBlock = new ByteBlock())
|
||||
{
|
||||
this.Build(byteBlock);
|
||||
return byteBlock.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -196,6 +196,18 @@ namespace ThingsGateway.Foundation.Http
|
||||
this.Responsed = responsed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 输出
|
||||
/// </summary>
|
||||
public override string ToString()
|
||||
{
|
||||
using (var byteBlock = new ByteBlock())
|
||||
{
|
||||
this.Build(byteBlock, false);
|
||||
return byteBlock.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 构建数据为字节数组。
|
||||
/// </summary>
|
||||
|
||||
@@ -38,24 +38,17 @@ namespace ThingsGateway.Foundation.Http
|
||||
/// </summary>
|
||||
public class HttpClientBase : TcpClientBase, IHttpClient
|
||||
{
|
||||
private readonly object m_requestLocker = new object();
|
||||
private readonly WaitData<HttpResponse> m_waitData;
|
||||
#region 字段
|
||||
|
||||
private readonly SemaphoreSlim m_semaphoreForRequest = new SemaphoreSlim(1, 1);
|
||||
private readonly WaitData<HttpResponse> m_waitData = new WaitData<HttpResponse>();
|
||||
private readonly WaitDataAsync<HttpResponse> m_waitDataAsync = new WaitDataAsync<HttpResponse>();
|
||||
private bool m_getContent;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
public HttpClientBase()
|
||||
{
|
||||
this.m_waitData = new WaitData<HttpResponse>();
|
||||
}
|
||||
#endregion 字段
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
/// <param name="timeout"></param>
|
||||
/// <returns></returns>
|
||||
public override ITcpClient Connect(int timeout = 5000)
|
||||
public override void Connect(int timeout, CancellationToken token)
|
||||
{
|
||||
if (this.Config.GetValue(HttpConfigExtensions.HttpProxyProperty) is HttpProxy httpProxy)
|
||||
{
|
||||
@@ -65,13 +58,13 @@ namespace ThingsGateway.Foundation.Http
|
||||
try
|
||||
{
|
||||
this.Config.SetRemoteIPHost(proxyHost);
|
||||
base.Connect(timeout);
|
||||
base.Connect(timeout, token);
|
||||
var request = new HttpRequest();
|
||||
request.InitHeaders()
|
||||
.SetHost(remoteHost.Host)
|
||||
.SetUrl(remoteHost.Host, true)
|
||||
.SetProxyHost(remoteHost.Host)
|
||||
.AsMethod("CONNECT");
|
||||
var response = this.Request(request, timeout: timeout);
|
||||
var response = this.Request(request, false, timeout, token);
|
||||
if (response.IsProxyAuthenticationRequired)
|
||||
{
|
||||
if (credential is null)
|
||||
@@ -90,10 +83,10 @@ namespace ThingsGateway.Foundation.Http
|
||||
if (!response.KeepAlive)
|
||||
{
|
||||
base.Close("代理要求关闭连接,随后重写连接。");
|
||||
base.Connect(timeout);
|
||||
base.Connect(timeout, token);
|
||||
}
|
||||
|
||||
response = this.Request(request, timeout: timeout);
|
||||
response = this.Request(request, false, timeout, token);
|
||||
}
|
||||
|
||||
if (response.StatusCode != 200)
|
||||
@@ -108,37 +101,85 @@ namespace ThingsGateway.Foundation.Http
|
||||
}
|
||||
else
|
||||
{
|
||||
base.Connect(timeout);
|
||||
base.Connect(timeout, token);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override async Task ConnectAsync(int timeout, CancellationToken token)
|
||||
{
|
||||
if (this.Config.GetValue(HttpConfigExtensions.HttpProxyProperty) is HttpProxy httpProxy)
|
||||
{
|
||||
var proxyHost = httpProxy.Host;
|
||||
var credential = httpProxy.Credential;
|
||||
var remoteHost = this.Config.GetValue(TouchSocketConfigExtension.RemoteIPHostProperty);
|
||||
try
|
||||
{
|
||||
this.Config.SetRemoteIPHost(proxyHost);
|
||||
await base.ConnectAsync(timeout, token);
|
||||
var request = new HttpRequest();
|
||||
request.InitHeaders()
|
||||
.SetHost(remoteHost.Host)
|
||||
.SetProxyHost(remoteHost.Host)
|
||||
.AsMethod("CONNECT");
|
||||
var response = await this.RequestAsync(request, false, timeout, token);
|
||||
if (response.IsProxyAuthenticationRequired)
|
||||
{
|
||||
if (credential is null)
|
||||
{
|
||||
throw new Exception("未指定代理的凭据。");
|
||||
}
|
||||
var authHeader = response.Headers.Get(HttpHeaders.ProxyAuthenticate);
|
||||
if (authHeader.IsNullOrEmpty())
|
||||
{
|
||||
throw new Exception("未指定代理身份验证质询。");
|
||||
}
|
||||
|
||||
var ares = new AuthenticationChallenge(authHeader, credential);
|
||||
|
||||
request.Headers.Add(HttpHeaders.ProxyAuthorization, ares.ToString());
|
||||
if (!response.KeepAlive)
|
||||
{
|
||||
base.Close("代理要求关闭连接,随后重写连接。");
|
||||
await base.ConnectAsync(timeout, token);
|
||||
}
|
||||
|
||||
response = await this.RequestAsync(request, timeout: timeout);
|
||||
}
|
||||
|
||||
if (response.StatusCode != 200)
|
||||
{
|
||||
throw new Exception(response.StatusMessage);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.Config.SetRemoteIPHost(remoteHost);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
await base.ConnectAsync(timeout, token);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
/// <param name="request"><inheritdoc/></param>
|
||||
/// <param name="onlyRequest"><inheritdoc/></param>
|
||||
/// <param name="timeout"><inheritdoc/></param>
|
||||
/// <param name="token"><inheritdoc/></param>
|
||||
/// <returns></returns>
|
||||
public HttpResponse Request(HttpRequest request, bool onlyRequest = false, int timeout = 10 * 1000, CancellationToken token = default)
|
||||
{
|
||||
lock (this.m_requestLocker)
|
||||
try
|
||||
{
|
||||
this.m_semaphoreForRequest.Wait(token);
|
||||
this.m_getContent = false;
|
||||
using (var byteBlock = new ByteBlock())
|
||||
{
|
||||
request.Build(byteBlock);
|
||||
|
||||
this.m_waitData.Reset();
|
||||
this.m_waitData.SetCancellationToken(token);
|
||||
|
||||
this.Reset(token);
|
||||
this.DefaultSend(byteBlock);
|
||||
if (onlyRequest)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
switch (this.m_waitData.Wait(timeout))
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
@@ -147,8 +188,7 @@ namespace ThingsGateway.Foundation.Http
|
||||
case WaitDataStatus.Overtime:
|
||||
throw new TimeoutException(TouchSocketHttpResource.Overtime.GetDescription());
|
||||
case WaitDataStatus.Canceled:
|
||||
return default;
|
||||
|
||||
throw new OperationCanceledException();
|
||||
case WaitDataStatus.Default:
|
||||
case WaitDataStatus.Disposed:
|
||||
default:
|
||||
@@ -156,27 +196,62 @@ namespace ThingsGateway.Foundation.Http
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.m_semaphoreForRequest.Release();
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<HttpResponse> RequestAsync(HttpRequest request, bool onlyRequest = false, int timeout = 10 * 1000, CancellationToken token = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
await this.m_semaphoreForRequest.WaitAsync(timeout, token);
|
||||
this.m_getContent = false;
|
||||
using (var byteBlock = new ByteBlock())
|
||||
{
|
||||
request.Build(byteBlock);
|
||||
|
||||
this.Reset(token);
|
||||
await this.DefaultSendAsync(byteBlock);
|
||||
if (onlyRequest)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
switch (await this.m_waitDataAsync.WaitAsync(timeout))
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
return this.m_waitDataAsync.WaitResult;
|
||||
case WaitDataStatus.Overtime:
|
||||
throw new TimeoutException(TouchSocketHttpResource.Overtime.GetDescription());
|
||||
case WaitDataStatus.Canceled:
|
||||
throw new OperationCanceledException();
|
||||
case WaitDataStatus.Default:
|
||||
case WaitDataStatus.Disposed:
|
||||
default:
|
||||
throw new Exception(TouchSocketHttpResource.UnknownError.GetDescription());
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.m_semaphoreForRequest.Release();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <param name="onlyRequest"></param>
|
||||
/// <param name="timeout"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
public HttpResponse RequestContent(HttpRequest request, bool onlyRequest = false, int timeout = 10 * 1000, CancellationToken token = default)
|
||||
{
|
||||
lock (this.m_requestLocker)
|
||||
try
|
||||
{
|
||||
this.m_semaphoreForRequest.Wait(token);
|
||||
this.m_getContent = true;
|
||||
using (var byteBlock = new ByteBlock())
|
||||
{
|
||||
request.Build(byteBlock);
|
||||
|
||||
this.m_waitData.Reset();
|
||||
this.m_waitData.SetCancellationToken(token);
|
||||
this.Reset(token);
|
||||
|
||||
this.DefaultSend(byteBlock);
|
||||
if (onlyRequest)
|
||||
@@ -188,12 +263,10 @@ namespace ThingsGateway.Foundation.Http
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
return this.m_waitData.WaitResult;
|
||||
|
||||
case WaitDataStatus.Overtime:
|
||||
throw new TimeoutException(TouchSocketHttpResource.Overtime.GetDescription());
|
||||
case WaitDataStatus.Canceled:
|
||||
return default;
|
||||
|
||||
throw new OperationCanceledException();
|
||||
case WaitDataStatus.Default:
|
||||
case WaitDataStatus.Disposed:
|
||||
default:
|
||||
@@ -201,6 +274,50 @@ namespace ThingsGateway.Foundation.Http
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.m_semaphoreForRequest.Release();
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<HttpResponse> RequestContentAsync(HttpRequest request, bool onlyRequest = false, int timeout = 10 * 1000, CancellationToken token = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
await this.m_semaphoreForRequest.WaitAsync(timeout, token);
|
||||
this.m_getContent = true;
|
||||
using (var byteBlock = new ByteBlock())
|
||||
{
|
||||
request.Build(byteBlock);
|
||||
|
||||
this.Reset(token);
|
||||
|
||||
await this.DefaultSendAsync(byteBlock);
|
||||
if (onlyRequest)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
switch (await this.m_waitDataAsync.WaitAsync(timeout))
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
return this.m_waitData.WaitResult;
|
||||
case WaitDataStatus.Overtime:
|
||||
throw new TimeoutException(TouchSocketHttpResource.Overtime.GetDescription());
|
||||
case WaitDataStatus.Canceled:
|
||||
throw new OperationCanceledException();
|
||||
case WaitDataStatus.Default:
|
||||
case WaitDataStatus.Disposed:
|
||||
default:
|
||||
throw new Exception(TouchSocketHttpResource.UnknownError.GetDescription());
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.m_semaphoreForRequest.Release();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -213,22 +330,6 @@ namespace ThingsGateway.Foundation.Http
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override Task ReceivedData(ReceivedDataEventArgs e)
|
||||
{
|
||||
if (e.RequestInfo is HttpResponse response)
|
||||
{
|
||||
if (this.m_getContent)
|
||||
{
|
||||
response.TryGetContent(out _);
|
||||
}
|
||||
this.m_waitData.Set(response);
|
||||
}
|
||||
|
||||
return base.ReceivedData(e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
@@ -239,5 +340,42 @@ namespace ThingsGateway.Foundation.Http
|
||||
this.SetDataHandlingAdapter(new HttpClientDataHandlingAdapter());
|
||||
await base.OnConnecting(e);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override async Task OnDisconnected(DisconnectEventArgs e)
|
||||
{
|
||||
this.m_waitData.Cancel();
|
||||
this.m_waitDataAsync.Cancel();
|
||||
await base.OnDisconnected(e);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override Task ReceivedData(ReceivedDataEventArgs e)
|
||||
{
|
||||
if (e.RequestInfo is HttpResponse response)
|
||||
{
|
||||
if (this.m_getContent)
|
||||
{
|
||||
response.TryGetContent(out _);
|
||||
}
|
||||
this.Set(response);
|
||||
}
|
||||
|
||||
return base.ReceivedData(e);
|
||||
}
|
||||
|
||||
private void Reset(CancellationToken token)
|
||||
{
|
||||
this.m_waitData.Reset();
|
||||
this.m_waitDataAsync.Reset();
|
||||
this.m_waitData.SetCancellationToken(token);
|
||||
this.m_waitDataAsync.SetCancellationToken(token);
|
||||
}
|
||||
|
||||
private void Set(HttpResponse response)
|
||||
{
|
||||
this.m_waitData.Set(response);
|
||||
this.m_waitDataAsync.Set(response);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace ThingsGateway.Foundation.Http
|
||||
{
|
||||
/// <summary>
|
||||
/// HttpClient客户端连接池
|
||||
/// </summary>
|
||||
public class HttpClientPool : SetupConfigObject
|
||||
{
|
||||
private readonly ConcurrentStack<HttpClient> m_httpClients = new ConcurrentStack<HttpClient>();
|
||||
|
||||
/// <summary>
|
||||
/// 最大连接数量。
|
||||
/// </summary>
|
||||
public int MaxCount { get; set; } = 10;
|
||||
|
||||
/// <summary>
|
||||
/// 目标地址
|
||||
/// </summary>
|
||||
public IPHost RemoteIPHost { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 清除现有的所有链接
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
while (this.m_httpClients.TryPop(out var client))
|
||||
{
|
||||
client.SafeDispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发起请求,并获取数据体
|
||||
/// </summary>
|
||||
/// <param name="request">请求体</param>
|
||||
/// <param name="timeout">等待超时时间</param>
|
||||
/// <param name="token">结束等待令箭</param>
|
||||
/// <returns></returns>
|
||||
public HttpResponse RequestContent(HttpRequest request, int timeout = 10 * 1000, CancellationToken token = default)
|
||||
{
|
||||
var client = this.GetHttpClient();
|
||||
try
|
||||
{
|
||||
return client.RequestContent(request, false, timeout, token);
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.ReturnHttpClient(client);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发起请求,并获取数据体
|
||||
/// </summary>
|
||||
/// <param name="request">请求体</param>
|
||||
/// <param name="timeout">等待超时时间</param>
|
||||
/// <param name="token">结束等待令箭</param>
|
||||
/// <returns></returns>
|
||||
public async Task<HttpResponse> RequestContentAsync(HttpRequest request, int timeout = 10000, CancellationToken token = default)
|
||||
{
|
||||
var client = await this.GetHttpClientAsync();
|
||||
try
|
||||
{
|
||||
return await client.RequestContentAsync(request, false, timeout, token);
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.ReturnHttpClient(client);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
this.Clear();
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void LoadConfig(TouchSocketConfig config)
|
||||
{
|
||||
this.RemoteIPHost = config.GetValue(TouchSocketConfigExtension.RemoteIPHostProperty) ?? throw new ArgumentNullException(nameof(this.RemoteIPHost));
|
||||
base.LoadConfig(config);
|
||||
}
|
||||
|
||||
private HttpClient GetHttpClient()
|
||||
{
|
||||
this.ThrowIfDisposed();
|
||||
HttpClient client;
|
||||
while (this.m_httpClients.TryPop(out client))
|
||||
{
|
||||
if (client.Online)
|
||||
{
|
||||
return client;
|
||||
}
|
||||
else
|
||||
{
|
||||
client.SafeDispose();
|
||||
}
|
||||
}
|
||||
|
||||
client = new HttpClient();
|
||||
client.Setup(this.Config.Clone());
|
||||
client.Connect();
|
||||
return client;
|
||||
}
|
||||
|
||||
private async Task<HttpClient> GetHttpClientAsync()
|
||||
{
|
||||
this.ThrowIfDisposed();
|
||||
HttpClient client;
|
||||
while (this.m_httpClients.TryPop(out client))
|
||||
{
|
||||
if (client.Online)
|
||||
{
|
||||
return client;
|
||||
}
|
||||
else
|
||||
{
|
||||
client.SafeDispose();
|
||||
}
|
||||
}
|
||||
|
||||
client = new HttpClient();
|
||||
client.Setup(this.Config.Clone());
|
||||
await client.ConnectAsync();
|
||||
return client;
|
||||
}
|
||||
|
||||
private void ReturnHttpClient(HttpClient client)
|
||||
{
|
||||
if (!client.Online || this.m_httpClients.Count >= 10)
|
||||
{
|
||||
client.SafeDispose();
|
||||
return;
|
||||
}
|
||||
this.m_httpClients.Push(client);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,17 +18,15 @@ using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using ThingsGateway.Foundation.Core;
|
||||
using ThingsGateway.Foundation.Sockets;
|
||||
|
||||
using HttpClient = System.Net.Http.HttpClient;
|
||||
using HttpMethod = System.Net.Http.HttpMethod;
|
||||
using ThingsGateway.Foundation.Sockets;
|
||||
|
||||
namespace ThingsGateway.Foundation.Http
|
||||
{
|
||||
/// <summary>
|
||||
/// 这是基于<see cref="System.Net.Http.HttpClient"/>的通讯模型。
|
||||
/// </summary>
|
||||
public class HttpClientSlim : DisposableObject
|
||||
public class HttpClientSlim : SetupConfigObject
|
||||
{
|
||||
private readonly System.Net.Http.HttpClient m_httpClient;
|
||||
|
||||
@@ -42,106 +40,16 @@ namespace ThingsGateway.Foundation.Http
|
||||
this.m_httpClient = httpClient;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 配置
|
||||
/// </summary>
|
||||
public TouchSocketConfig Config { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Ioc容器
|
||||
/// </summary>
|
||||
public IContainer Container { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 插件管理器
|
||||
/// </summary>
|
||||
public IPluginsManager PluginsManager { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 日志记录器
|
||||
/// </summary>
|
||||
public ILog Logger { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 通讯客户端
|
||||
/// </summary>
|
||||
public System.Net.Http.HttpClient HttpClient => this.m_httpClient;
|
||||
|
||||
/// <summary>
|
||||
/// 加载配置
|
||||
/// </summary>
|
||||
/// <param name="config"></param>
|
||||
protected virtual void LoadConfig(TouchSocketConfig config)
|
||||
/// <inheritdoc/>
|
||||
protected override void LoadConfig(TouchSocketConfig config)
|
||||
{
|
||||
this.m_httpClient.BaseAddress ??= config.GetValue(TouchSocketConfigExtension.RemoteIPHostProperty);
|
||||
this.Logger ??= this.Container.Resolve<ILog>();
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 配置
|
||||
/// </summary>
|
||||
/// <param name="config"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="ArgumentNullException"></exception>
|
||||
public HttpClientSlim Setup(TouchSocketConfig config)
|
||||
{
|
||||
if (config == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(config));
|
||||
}
|
||||
|
||||
this.ThrowIfDisposed();
|
||||
|
||||
this.BuildConfig(config);
|
||||
|
||||
this.PluginsManager.Raise(nameof(ILoadingConfigPlugin.OnLoadingConfig), this, new ConfigEventArgs(config));
|
||||
this.LoadConfig(this.Config);
|
||||
this.PluginsManager.Raise(nameof(ILoadedConfigPlugin.OnLoadedConfig), this, new ConfigEventArgs(config));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
private void BuildConfig(TouchSocketConfig config)
|
||||
{
|
||||
this.Config = config;
|
||||
|
||||
if (!(config.GetValue(TouchSocketCoreConfigExtension.ContainerProperty) is IContainer container))
|
||||
{
|
||||
container = new Container();
|
||||
}
|
||||
|
||||
if (!container.IsRegistered(typeof(ILog)))
|
||||
{
|
||||
container.RegisterSingleton<ILog, LoggerGroup>();
|
||||
}
|
||||
|
||||
if (!(config.GetValue(TouchSocketCoreConfigExtension.PluginsManagerProperty) is IPluginsManager pluginsManager))
|
||||
{
|
||||
pluginsManager = new PluginsManager(container);
|
||||
}
|
||||
|
||||
if (container.IsRegistered(typeof(IPluginsManager)))
|
||||
{
|
||||
pluginsManager = container.Resolve<IPluginsManager>();
|
||||
}
|
||||
else
|
||||
{
|
||||
container.RegisterSingleton<IPluginsManager>(pluginsManager);
|
||||
}
|
||||
|
||||
if (config.GetValue(TouchSocketCoreConfigExtension.ConfigureContainerProperty) is Action<IContainer> actionContainer)
|
||||
{
|
||||
actionContainer.Invoke(container);
|
||||
}
|
||||
|
||||
if (config.GetValue(TouchSocketCoreConfigExtension.ConfigurePluginsProperty) is Action<IPluginsManager> actionPluginsManager)
|
||||
{
|
||||
pluginsManager.Enable = true;
|
||||
actionPluginsManager.Invoke(pluginsManager);
|
||||
}
|
||||
this.Container = container;
|
||||
this.PluginsManager = pluginsManager;
|
||||
base.LoadConfig(config);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,16 @@ namespace ThingsGateway.Foundation.Http
|
||||
/// <returns></returns>
|
||||
HttpResponse Request(HttpRequest request, bool onlyRequest = false, int timeout = 10 * 1000, CancellationToken token = default);
|
||||
|
||||
/// <summary>
|
||||
/// 发起请求
|
||||
/// </summary>
|
||||
/// <param name="request">请求体</param>
|
||||
/// <param name="onlyRequest">仅仅请求,而不等待结果</param>
|
||||
/// <param name="timeout">等待超时时间</param>
|
||||
/// <param name="token">结束等待令箭</param>
|
||||
/// <returns></returns>
|
||||
Task<HttpResponse> RequestAsync(HttpRequest request, bool onlyRequest = false, int timeout = 10000, CancellationToken token = default);
|
||||
|
||||
/// <summary>
|
||||
/// 发起请求,并获取数据体
|
||||
/// </summary>
|
||||
@@ -49,5 +59,15 @@ namespace ThingsGateway.Foundation.Http
|
||||
/// <param name="token">结束等待令箭</param>
|
||||
/// <returns></returns>
|
||||
public HttpResponse RequestContent(HttpRequest request, bool onlyRequest = false, int timeout = 10 * 1000, CancellationToken token = default);
|
||||
|
||||
/// <summary>
|
||||
/// 发起请求,并获取数据体
|
||||
/// </summary>
|
||||
/// <param name="request">请求体</param>
|
||||
/// <param name="onlyRequest">仅仅请求,而不等待结果</param>
|
||||
/// <param name="timeout">等待超时时间</param>
|
||||
/// <param name="token">结束等待令箭</param>
|
||||
/// <returns></returns>
|
||||
Task<HttpResponse> RequestContentAsync(HttpRequest request, bool onlyRequest = false, int timeout = 10000, CancellationToken token = default);
|
||||
}
|
||||
}
|
||||
@@ -23,10 +23,13 @@
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// HTTP上下文事件委托
|
||||
/// </summary>
|
||||
/// <typeparam name="TClient"></typeparam>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="e"></param>
|
||||
public delegate void HttpContextEventHandler<TClient>(TClient client, HttpContextEventArgs e);
|
||||
namespace ThingsGateway.Foundation.Http
|
||||
{
|
||||
/// <summary>
|
||||
/// HTTP上下文事件委托
|
||||
/// </summary>
|
||||
/// <typeparam name="TClient"></typeparam>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="e"></param>
|
||||
public delegate Task HttpContextEventHandler<TClient>(TClient client, HttpContextEventArgs e);
|
||||
}
|
||||
|
||||
@@ -45,6 +45,33 @@ namespace ThingsGateway.Foundation.Http
|
||||
|
||||
#region HttpBase
|
||||
|
||||
/// <summary>
|
||||
/// 添加Header参数
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static TRequest AddHeader<TRequest>(this TRequest request, string key, string value) where TRequest : HttpBase
|
||||
{
|
||||
request.Headers.Add(key, value);
|
||||
return request;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加Header参数
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static TRequest AddHeader<TRequest>(this TRequest request, HttpHeaders key, string value) where TRequest : HttpBase
|
||||
{
|
||||
request.Headers.Add(key, value);
|
||||
return request;
|
||||
}
|
||||
|
||||
|
||||
#region 设置内容
|
||||
|
||||
/// <summary>
|
||||
@@ -220,6 +247,19 @@ namespace ThingsGateway.Foundation.Http
|
||||
return request;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加Query参数
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static TRequest AddQuery<TRequest>(this TRequest request, string key, string value) where TRequest : HttpRequest
|
||||
{
|
||||
request.Query.Add(key, value);
|
||||
return request;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 对比不包含参数的Url。其中有任意一方为null,则均返回False。
|
||||
/// </summary>
|
||||
@@ -228,9 +268,14 @@ namespace ThingsGateway.Foundation.Http
|
||||
/// <returns></returns>
|
||||
public static bool UrlEquals<TRequest>(this TRequest request, string url) where TRequest : HttpRequest
|
||||
{
|
||||
return string.IsNullOrEmpty(request.RelativeURL) || string.IsNullOrEmpty(url)
|
||||
? false
|
||||
: request.RelativeURL.Equals(url, StringComparison.CurrentCultureIgnoreCase);
|
||||
if (string.IsNullOrEmpty(request.RelativeURL) || string.IsNullOrEmpty(url))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return request.RelativeURL.Equals(url, StringComparison.CurrentCultureIgnoreCase);
|
||||
}
|
||||
}
|
||||
|
||||
#region 设置函数
|
||||
@@ -374,11 +419,32 @@ namespace ThingsGateway.Foundation.Http
|
||||
/// <returns></returns>
|
||||
public static TResponse SetContentTypeFromFileName<TResponse>(this TResponse response, string fileName) where TResponse : HttpResponse
|
||||
{
|
||||
var contentDisposition = $"attachment;filename={System.Web.HttpUtility.UrlEncode(fileName)}";
|
||||
var contentDisposition = "attachment;" + "filename=" + System.Web.HttpUtility.UrlEncode(fileName);
|
||||
response.Headers.Add(HttpHeaders.ContentDisposition, contentDisposition);
|
||||
return response;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 判断返回的状态码是否为成功。
|
||||
/// </summary>
|
||||
/// <param name="response"></param>
|
||||
/// <param name="status">
|
||||
/// 当不指定具体的状态码时,只要状态码在200-299之间则为<see langword="true"/>。
|
||||
/// 当指定时,状态码不仅必须要在200-299之间,还必须是指定的状态码才会返回<see langword="true"/>。
|
||||
/// </param>
|
||||
/// <returns></returns>
|
||||
public static bool IsSuccess<TResponse>(this TResponse response, int? status = default) where TResponse : HttpResponse
|
||||
{
|
||||
if (status.HasValue)
|
||||
{
|
||||
return response.StatusCode == status && response.StatusCode >= 200 && response.StatusCode < 300;
|
||||
}
|
||||
else
|
||||
{
|
||||
return response.StatusCode >= 200 && response.StatusCode < 300;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置状态,并且附带时间戳。
|
||||
/// </summary>
|
||||
@@ -402,8 +468,8 @@ namespace ThingsGateway.Foundation.Http
|
||||
/// <returns></returns>
|
||||
public static TResponse UrlNotFind<TResponse>(this TResponse response) where TResponse : HttpResponse
|
||||
{
|
||||
response.SetContent("<html><body><h1>404 -RRQM Not Found</h1></body></html>");
|
||||
response.StatusCode = 404;
|
||||
response.SetContent("<html><body><h1>404 -Not Found</h1></body></html>");
|
||||
response.SetStatus(404, "Not Found");
|
||||
response.ContentType = "text/html;charset=utf-8";
|
||||
return response;
|
||||
}
|
||||
@@ -429,7 +495,7 @@ namespace ThingsGateway.Foundation.Http
|
||||
using (var reader = FilePool.GetReader(filePath))
|
||||
{
|
||||
response.SetContentTypeByExtension(Path.GetExtension(filePath));
|
||||
var contentDisposition = $"attachment;filename={System.Web.HttpUtility.UrlEncode(fileName ?? Path.GetFileName(filePath))}";
|
||||
var contentDisposition = "attachment;" + "filename=" + System.Web.HttpUtility.UrlEncode(fileName ?? Path.GetFileName(filePath));
|
||||
response.Headers.Add(HttpHeaders.ContentDisposition, contentDisposition);
|
||||
response.Headers.Add(HttpHeaders.AcceptRanges, "bytes");
|
||||
|
||||
@@ -526,7 +592,7 @@ namespace ThingsGateway.Foundation.Http
|
||||
using (var reader = FilePool.GetReader(filePath))
|
||||
{
|
||||
context.Response.SetContentTypeByExtension(Path.GetExtension(filePath));
|
||||
var contentDisposition = $"attachment;filename={System.Web.HttpUtility.UrlEncode(fileName ?? Path.GetFileName(filePath))}";
|
||||
var contentDisposition = "attachment;" + "filename=" + System.Web.HttpUtility.UrlEncode(fileName ?? Path.GetFileName(filePath));
|
||||
context.Response.Headers.Add(HttpHeaders.ContentDisposition, contentDisposition);
|
||||
context.Response.Headers.Add(HttpHeaders.AcceptRanges, "bytes");
|
||||
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace ThingsGateway.Foundation.Http
|
||||
{
|
||||
/// <summary>
|
||||
/// IHttpDeletePlugin
|
||||
/// </summary>
|
||||
[Obsolete("该插件已被弃用,请考虑使用“IHttpPlugin”插件代替使用。本插件将在正式版发布时直接移除。", true)]
|
||||
public interface IHttpDeletePlugin<in TClient> : IPlugin where TClient : IHttpSocketClient
|
||||
{
|
||||
/// <summary>
|
||||
/// 在收到Delete时
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="e"></param>
|
||||
/// <returns></returns>
|
||||
Task OnHttpDelete(TClient client, HttpContextEventArgs e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// IHttpDeletePlugin
|
||||
/// </summary>
|
||||
[Obsolete("该插件已被弃用,请考虑使用“IHttpPlugin”插件代替使用。本插件将在正式版发布时直接移除。", true)]
|
||||
public interface IHttpDeletePlugin : IHttpDeletePlugin<IHttpSocketClient>
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace ThingsGateway.Foundation.Http
|
||||
{
|
||||
/// <summary>
|
||||
/// IHttpGetPlugin
|
||||
/// </summary>
|
||||
[Obsolete("该插件已被弃用,请考虑使用“IHttpPlugin”插件代替使用。本插件将在正式版发布时直接移除。", true)]
|
||||
public interface IHttpGetPlugin<in TClient> : IPlugin where TClient : IHttpSocketClient
|
||||
{
|
||||
/// <summary>
|
||||
/// 在收到Get时
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="e"></param>
|
||||
/// <returns></returns>
|
||||
Task OnHttpGet(TClient client, HttpContextEventArgs e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// IHttpGetPlugin
|
||||
/// </summary>
|
||||
[Obsolete("该插件已被弃用,请考虑使用“IHttpPlugin”插件代替使用。本插件将在正式版发布时直接移除。", true)]
|
||||
public interface IHttpGetPlugin : IHttpGetPlugin<IHttpSocketClient>
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -31,7 +31,8 @@ namespace ThingsGateway.Foundation.Http
|
||||
public interface IHttpPlugin<in TClient> : IPlugin where TClient : IHttpSocketClient
|
||||
{
|
||||
/// <summary>
|
||||
/// 在收到Http请求时
|
||||
/// 在收到Http请求时。注意:此插件的执行在<see cref="IHttpGetPlugin"/>,<see cref="IHttpPostPlugin"/>,
|
||||
/// <see cref="IHttpDeletePlugin"/>,<see cref="IHttpPutPlugin"/>之前。
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="e"></param>
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace ThingsGateway.Foundation.Http
|
||||
{
|
||||
/// <summary>
|
||||
/// IHttpPostPlugin
|
||||
/// </summary>
|
||||
[Obsolete("该插件已被弃用,请考虑使用“IHttpPlugin”插件代替使用。本插件将在正式版发布时直接移除。", true)]
|
||||
public interface IHttpPostPlugin<in TClient> : IPlugin where TClient : IHttpSocketClient
|
||||
{
|
||||
/// <summary>
|
||||
/// 在收到Post时
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="e"></param>
|
||||
/// <returns></returns>
|
||||
Task OnHttpPost(TClient client, HttpContextEventArgs e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// IHttpPostPlugin
|
||||
/// </summary>
|
||||
[Obsolete("该插件已被弃用,请考虑使用“IHttpPlugin”插件代替使用。本插件将在正式版发布时直接移除。", true)]
|
||||
public interface IHttpPostPlugin : IHttpPostPlugin<IHttpSocketClient>
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace ThingsGateway.Foundation.Http
|
||||
{
|
||||
/// <summary>
|
||||
/// IHttpPutPlugin
|
||||
/// </summary>
|
||||
[Obsolete("该插件已被弃用,请考虑使用“IHttpPlugin”插件代替使用。本插件将在正式版发布时直接移除。", true)]
|
||||
public interface IHttpPutPlugin<in TClient> : IPlugin where TClient : IHttpSocketClient
|
||||
{
|
||||
/// <summary>
|
||||
/// 在收到Put时
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="e"></param>
|
||||
/// <returns></returns>
|
||||
Task OnHttpPut(TClient client, HttpContextEventArgs e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// IHttpPutPlugin
|
||||
/// </summary>
|
||||
[Obsolete("该插件已被弃用,请考虑使用“IHttpPlugin”插件代替使用。本插件将在正式版发布时直接移除。", true)]
|
||||
public interface IHttpPutPlugin : IHttpPutPlugin<IHttpSocketClient>
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -37,6 +37,10 @@ namespace ThingsGateway.Foundation.Http
|
||||
public HttpStaticPagePlugin()
|
||||
{
|
||||
this.FileCache = new FileCachePool();
|
||||
this.SetNavigateAction(request =>
|
||||
{
|
||||
return request.RelativeURL;
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -81,15 +85,46 @@ namespace ThingsGateway.Foundation.Http
|
||||
this.FileCache.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 重新导航
|
||||
/// </summary>
|
||||
public Func<HttpRequest, Task<string>> NavigateAction { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 设定重新导航
|
||||
/// </summary>
|
||||
/// <param name="func"></param>
|
||||
/// <returns></returns>
|
||||
public HttpStaticPagePlugin SetNavigateAction(Func<HttpRequest, Task<string>> func)
|
||||
{
|
||||
this.NavigateAction = func;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设定重新导航
|
||||
/// </summary>
|
||||
/// <param name="func"></param>
|
||||
/// <returns></returns>
|
||||
public HttpStaticPagePlugin SetNavigateAction(Func<HttpRequest, string> func)
|
||||
{
|
||||
this.NavigateAction = (request) =>
|
||||
{
|
||||
return Task.FromResult(func(request));
|
||||
};
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task OnHttpRequest(IHttpSocketClient client, HttpContextEventArgs e)
|
||||
{
|
||||
if (this.FileCache.Find(e.Context.Request.RelativeURL, out var data))
|
||||
var url = await this.NavigateAction.Invoke(e.Context.Request);
|
||||
if (this.FileCache.Find(url, out var data))
|
||||
{
|
||||
e.Context.Response.SetStatus();
|
||||
if (this.ContentTypeProvider?.TryGetContentType(e.Context.Request.RelativeURL, out var result) != true)
|
||||
if (this.ContentTypeProvider?.TryGetContentType(url, out var result) != true)
|
||||
{
|
||||
result = HttpTools.GetContentTypeFromExtension(e.Context.Request.RelativeURL);
|
||||
result = HttpTools.GetContentTypeFromExtension(url);
|
||||
}
|
||||
e.Context.Response.ContentType = result;
|
||||
e.Context.Response.SetContentLength(data.Length)
|
||||
|
||||
@@ -75,6 +75,7 @@ namespace ThingsGateway.Foundation.Http.WebSockets
|
||||
await this.m_resetEventForRead.WaitOneAsync(token).ConfigureFalseAwait();
|
||||
return new WebSocketReceiveResult(this.ComplateRead, this.m_dataFrame);
|
||||
}
|
||||
|
||||
#if NET6_0_OR_GREATER
|
||||
public async ValueTask<WebSocketReceiveResult> ValueReadAsync(CancellationToken token)
|
||||
{
|
||||
@@ -86,7 +87,9 @@ namespace ThingsGateway.Foundation.Http.WebSockets
|
||||
return new WebSocketReceiveResult(this.ComplateRead, this.m_dataFrame);
|
||||
}
|
||||
#endif
|
||||
|
||||
#region 发送
|
||||
|
||||
public void Send(WSDataFrame dataFrame, bool endOfMessage = true)
|
||||
{
|
||||
this.m_client.SendWithWS(dataFrame, endOfMessage);
|
||||
@@ -132,7 +135,7 @@ namespace ThingsGateway.Foundation.Http.WebSockets
|
||||
return this.m_client.SendWithWSAsync(dataFrame, endOfMessage);
|
||||
}
|
||||
|
||||
#endregion
|
||||
#endregion 发送
|
||||
|
||||
public async Task<bool> TryInputReceiveAsync(WSDataFrame dataFrame)
|
||||
{
|
||||
|
||||
@@ -30,11 +30,10 @@ namespace ThingsGateway.Foundation.Http.WebSockets
|
||||
this.DataFrame = dataFrame;
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
{
|
||||
m_disAction?.Invoke();
|
||||
this.m_disAction?.Invoke();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -47,4 +46,4 @@ namespace ThingsGateway.Foundation.Http.WebSockets
|
||||
/// </summary>
|
||||
public bool IsClosed => this.DataFrame == null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -35,18 +35,14 @@ namespace ThingsGateway.Foundation.Http.WebSockets
|
||||
/// </summary>
|
||||
public WSDataFrameEventHandler<WebSocketClient> Received { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
/// <param name="dataFrame"></param>
|
||||
protected override async Task OnReceivedWSDataFrame(WSDataFrame dataFrame)
|
||||
protected override Task OnReceivedWSDataFrame(WSDataFrameEventArgs e)
|
||||
{
|
||||
if (this.Received != null)
|
||||
{
|
||||
await this.Received.Invoke(this, dataFrame);
|
||||
return this.Received.Invoke(this, e);
|
||||
}
|
||||
|
||||
await base.OnReceivedWSDataFrame(dataFrame);
|
||||
return base.OnReceivedWSDataFrame(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,35 +52,27 @@ namespace ThingsGateway.Foundation.Http.WebSockets
|
||||
public class WebSocketClientBase : HttpClientBase, IWebSocketClient
|
||||
{
|
||||
#region Connect
|
||||
|
||||
/// <summary>
|
||||
/// 请求连接到WebSocket。
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override ITcpClient Connect(int timeout = 5000)
|
||||
{
|
||||
return this.Connect(default, timeout);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// 连接到ws服务器
|
||||
/// </summary>
|
||||
/// <param name="timeout"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
public virtual ITcpClient Connect(CancellationToken token, int timeout = 5000)
|
||||
/// <exception cref="WebSocketConnectException"></exception>
|
||||
public override void Connect(int timeout, CancellationToken token)
|
||||
{
|
||||
lock (this.SyncRoot)
|
||||
try
|
||||
{
|
||||
this.m_semaphoreSlim.Wait(token);
|
||||
if (!this.Online)
|
||||
{
|
||||
base.Connect(timeout);
|
||||
base.Connect(timeout, token);
|
||||
}
|
||||
|
||||
var iPHost = this.Config.GetValue(TouchSocketConfigExtension.RemoteIPHostProperty);
|
||||
var url = iPHost.PathAndQuery;
|
||||
var request = WSTools.GetWSRequest(this.RemoteIPHost.Host, url, this.GetWebSocketVersion(), out var base64Key);
|
||||
this.OnHandshaking(new HttpContextEventArgs(new HttpContext(request)));
|
||||
this.OnHandshaking(new HttpContextEventArgs(new HttpContext(request)))
|
||||
.GetFalseAwaitResult();
|
||||
|
||||
var response = this.Request(request, timeout: timeout, token: token);
|
||||
if (response.StatusCode != 101)
|
||||
@@ -101,47 +89,32 @@ namespace ThingsGateway.Foundation.Http.WebSockets
|
||||
this.SetAdapter(new WebSocketDataHandlingAdapter());
|
||||
this.SetValue(WebSocketFeature.HandshakedProperty, true);
|
||||
response.Flag = true;
|
||||
this.OnHandshaked(new HttpContextEventArgs(new HttpContext(request, response)));
|
||||
return this;
|
||||
Task.Factory.StartNew(PrivateOnHandshaked, new HttpContextEventArgs(new HttpContext(request, response)));
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.m_semaphoreSlim.Release();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
/// <param name="token"></param>
|
||||
/// <param name="timeout"></param>
|
||||
/// <returns></returns>
|
||||
public Task<ITcpClient> ConnectAsync(CancellationToken token, int timeout = 5000)
|
||||
{
|
||||
return Task.Run(() =>
|
||||
{
|
||||
return this.Connect(token, timeout);
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 请求连接到WebSocket。
|
||||
/// </summary>
|
||||
/// <param name="timeout"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="WebSocketConnectException"></exception>
|
||||
public override async Task<ITcpClient> ConnectAsync(int timeout = 5000)
|
||||
public override async Task ConnectAsync(int timeout, CancellationToken token)
|
||||
{
|
||||
try
|
||||
{
|
||||
await this.m_semaphoreSlim.WaitAsync();
|
||||
await this.m_semaphoreSlim.WaitAsync(timeout, token);
|
||||
if (!this.Online)
|
||||
{
|
||||
await base.ConnectAsync(timeout);
|
||||
await base.ConnectAsync(timeout, token);
|
||||
}
|
||||
|
||||
var iPHost = this.Config.GetValue(TouchSocketConfigExtension.RemoteIPHostProperty);
|
||||
var url = iPHost.PathAndQuery;
|
||||
var request = WSTools.GetWSRequest(this.RemoteIPHost.Host, url, this.GetWebSocketVersion(), out var base64Key);
|
||||
this.OnHandshaking(new HttpContextEventArgs(new HttpContext(request)));
|
||||
|
||||
var response = this.Request(request, false, timeout, CancellationToken.None);
|
||||
await this.OnHandshaking(new HttpContextEventArgs(new HttpContext(request)));
|
||||
|
||||
var response = await this.RequestAsync(request, timeout: timeout, token: token);
|
||||
if (response.StatusCode != 101)
|
||||
{
|
||||
throw new WebSocketConnectException($"协议升级失败,信息:{response.StatusMessage},更多信息请捕获WebSocketConnectException异常,获得HttpContext得知。", new HttpContext(request, response));
|
||||
@@ -156,15 +129,13 @@ namespace ThingsGateway.Foundation.Http.WebSockets
|
||||
this.SetAdapter(new WebSocketDataHandlingAdapter());
|
||||
this.SetValue(WebSocketFeature.HandshakedProperty, true);
|
||||
response.Flag = true;
|
||||
this.OnHandshaked(new HttpContextEventArgs(new HttpContext(request, response)));
|
||||
return this;
|
||||
_ = Task.Factory.StartNew(PrivateOnHandshaked, new HttpContextEventArgs(new HttpContext(request, response)));
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.m_semaphoreSlim.Release();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Connect
|
||||
|
||||
#region 字段
|
||||
@@ -185,67 +156,70 @@ namespace ThingsGateway.Foundation.Http.WebSockets
|
||||
/// </summary>
|
||||
public HttpContextEventHandler<WebSocketClientBase> Handshaking { get; set; }
|
||||
|
||||
private Task PrivateOnHandshaked(object obj)
|
||||
{
|
||||
return this.OnHandshaked((HttpContextEventArgs)obj);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 表示完成握手后。
|
||||
/// </summary>
|
||||
/// <param name="e"></param>
|
||||
protected virtual void OnHandshaked(HttpContextEventArgs e)
|
||||
protected virtual async Task OnHandshaked(HttpContextEventArgs e)
|
||||
{
|
||||
this.Handshaked?.Invoke(this, e);
|
||||
|
||||
_ = this.PluginsManager.RaiseAsync(nameof(IWebSocketHandshakedPlugin.OnWebSocketHandshaked), this, e);
|
||||
if (e.Handled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (this.Handshaked != null)
|
||||
{
|
||||
await this.Handshaked.Invoke(this, e);
|
||||
if (e.Handled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
await this.PluginsManager.RaiseAsync(nameof(IWebSocketHandshakedPlugin.OnWebSocketHandshaked), this, e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 表示在即将握手连接时。
|
||||
/// </summary>
|
||||
/// <param name="e"></param>
|
||||
protected virtual void OnHandshaking(HttpContextEventArgs e)
|
||||
protected virtual async Task OnHandshaking(HttpContextEventArgs e)
|
||||
{
|
||||
this.Handshaking?.Invoke(this, e);
|
||||
if (e.Handled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (this.PluginsManager.Raise(nameof(IWebSocketHandshakingPlugin.OnWebSocketHandshaking), this, e))
|
||||
if (this.Handshaking != null)
|
||||
{
|
||||
return;
|
||||
await this.Handshaking.Invoke(this, e).ConfigureFalseAwait();
|
||||
if (e.Handled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
await this.PluginsManager.RaiseAsync(nameof(IWebSocketHandshakingPlugin.OnWebSocketHandshaking), this, e).ConfigureFalseAwait();
|
||||
}
|
||||
|
||||
#endregion 事件
|
||||
|
||||
///// <inheritdoc/>
|
||||
//protected override bool HandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo)
|
||||
//{
|
||||
// if (this.GetHandshaked())
|
||||
// {
|
||||
// var dataFrame = (WSDataFrame)requestInfo;
|
||||
// this.OnReceivedWSDataFrame(dataFrame);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// if (requestInfo is HttpResponse response)
|
||||
// {
|
||||
// response.Flag = false;
|
||||
// base.HandleReceivedData(byteBlock, requestInfo);
|
||||
// SpinWait.SpinUntil(() =>
|
||||
// {
|
||||
// return (bool)response.Flag;
|
||||
// }, 3000);
|
||||
// }
|
||||
// }
|
||||
|
||||
// return false;
|
||||
//}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override async Task ReceivedData(ReceivedDataEventArgs e)
|
||||
{
|
||||
if (this.GetHandshaked())
|
||||
{
|
||||
var dataFrame = (WSDataFrame)e.RequestInfo;
|
||||
await this.OnReceivedWSDataFrame(dataFrame);
|
||||
|
||||
if (this.TryGetValue(WebSocketClientExtension.WebSocketProperty, out var internalWebSocket))
|
||||
{
|
||||
if (await internalWebSocket.TryInputReceiveAsync(dataFrame).ConfigureFalseAwait())
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
await this.OnReceivedWSDataFrame(new WSDataFrameEventArgs(dataFrame));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -280,21 +254,11 @@ namespace ThingsGateway.Foundation.Http.WebSockets
|
||||
/// <summary>
|
||||
/// 当收到WS数据时。
|
||||
/// </summary>
|
||||
/// <param name="dataFrame"></param>
|
||||
protected virtual async Task OnReceivedWSDataFrame(WSDataFrame dataFrame)
|
||||
/// <param name="e"></param>
|
||||
/// <returns></returns>
|
||||
protected virtual async Task OnReceivedWSDataFrame(WSDataFrameEventArgs e)
|
||||
{
|
||||
if (this.TryGetValue(WebSocketClientExtension.WebSocketProperty, out var internalWebSocket))
|
||||
{
|
||||
if (await internalWebSocket.TryInputReceiveAsync(dataFrame))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.PluginsManager.Enable)
|
||||
{
|
||||
await this.PluginsManager.RaiseAsync(nameof(IWebSocketReceivedPlugin.OnWebSocketReceived), this, new WSDataFrameEventArgs(dataFrame));
|
||||
}
|
||||
await this.PluginsManager.RaiseAsync(nameof(IWebSocketReceivedPlugin.OnWebSocketReceived), this, e).ConfigureFalseAwait();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -222,10 +222,7 @@ namespace ThingsGateway.Foundation.Http.WebSockets
|
||||
{
|
||||
case FilterResult.Cache:
|
||||
{
|
||||
if (this.m_tempByteBlock == null)
|
||||
{
|
||||
this.m_tempByteBlock = new ByteBlock();
|
||||
}
|
||||
this.m_tempByteBlock ??= new ByteBlock();
|
||||
this.m_tempByteBlock.Write(dataBuffer, offset, length - offset);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -29,6 +29,6 @@ namespace ThingsGateway.Foundation.Http.WebSockets
|
||||
/// 收到WebSocket数据
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="dataFrame"></param>
|
||||
public delegate Task WSDataFrameEventHandler<TClient>(TClient client, WSDataFrame dataFrame);
|
||||
/// <param name="e"></param>
|
||||
public delegate Task WSDataFrameEventHandler<TClient>(TClient client, WSDataFrameEventArgs e);
|
||||
}
|
||||
@@ -32,7 +32,7 @@ namespace ThingsGateway.Foundation.Http.WebSockets
|
||||
public class WebSocketConnectException : Exception
|
||||
{
|
||||
/// <summary>
|
||||
///构造函数
|
||||
/// WebSocket连接异常
|
||||
/// </summary>
|
||||
/// <param name="mes"></param>
|
||||
/// <param name="context"></param>
|
||||
|
||||
@@ -51,7 +51,7 @@ namespace ThingsGateway.Foundation.Http.WebSockets
|
||||
/// <summary>
|
||||
/// 获取显式WebSocket终端。
|
||||
/// <para>
|
||||
///
|
||||
///
|
||||
/// </para>
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
@@ -76,7 +76,9 @@ namespace ThingsGateway.Foundation.Http.WebSockets
|
||||
{
|
||||
client.RemoveValue(WebSocketProperty);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#endregion DependencyProperty
|
||||
|
||||
/// <summary>
|
||||
/// 发送Close报文。
|
||||
/// </summary>
|
||||
@@ -175,7 +177,6 @@ namespace ThingsGateway.Foundation.Http.WebSockets
|
||||
|
||||
#region 同步发送
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 采用WebSocket协议,发送二进制流数据。
|
||||
/// </summary>
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using ThingsGateway.Foundation.Http.WebSockets;
|
||||
|
||||
namespace ThingsGateway.Foundation.Sockets
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using ThingsGateway.Foundation.Http.WebSockets;
|
||||
|
||||
namespace ThingsGateway.Foundation.Core
|
||||
|
||||
@@ -15,13 +15,8 @@ namespace ThingsGateway.Foundation.Http.WebSockets
|
||||
/// <summary>
|
||||
/// IWebSocket
|
||||
/// </summary>
|
||||
public interface IWebSocket : IDisposable
|
||||
public interface IWebSocket : IDisposable, IHandshakeObject
|
||||
{
|
||||
/// <summary>
|
||||
/// 表示当前WebSocket是否已经完成连接。
|
||||
/// </summary>
|
||||
bool IsHandshaked { get; }
|
||||
|
||||
/// <summary>
|
||||
/// WebSocket版本
|
||||
/// </summary>
|
||||
@@ -68,6 +63,7 @@ namespace ThingsGateway.Foundation.Http.WebSockets
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
Task<WebSocketReceiveResult> ReadAsync(CancellationToken token);
|
||||
|
||||
#if NET6_0_OR_GREATER
|
||||
/// <summary>
|
||||
/// 值异步等待读取数据
|
||||
@@ -76,6 +72,7 @@ namespace ThingsGateway.Foundation.Http.WebSockets
|
||||
/// <returns></returns>
|
||||
public ValueTask<WebSocketReceiveResult> ValueReadAsync(CancellationToken token);
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// 采用WebSocket协议,发送WS数据。发送结束后,请及时释放<see cref="WSDataFrame"/>
|
||||
/// </summary>
|
||||
|
||||
@@ -30,20 +30,5 @@ namespace ThingsGateway.Foundation.Http.WebSockets
|
||||
/// </summary>
|
||||
public interface IWebSocketClient : IHttpClient
|
||||
{
|
||||
/// <summary>
|
||||
/// 连接到ws服务器
|
||||
/// </summary>
|
||||
/// <param name="token"></param>
|
||||
/// <param name="timeout"></param>
|
||||
/// <returns></returns>
|
||||
ITcpClient Connect(CancellationToken token, int timeout = 5000);
|
||||
|
||||
/// <summary>
|
||||
/// 异步连接到ws服务器
|
||||
/// </summary>
|
||||
/// <param name="token"></param>
|
||||
/// <param name="timeout"></param>
|
||||
/// <returns></returns>
|
||||
Task<ITcpClient> ConnectAsync(CancellationToken token, int timeout = 5000);
|
||||
}
|
||||
}
|
||||
@@ -107,9 +107,11 @@ namespace ThingsGateway.Foundation.Http.WebSockets
|
||||
await method.InvokeAsync(this, os);
|
||||
result = default;
|
||||
break;
|
||||
|
||||
case TaskReturnType.TaskObject:
|
||||
result = await method.InvokeObjectAsync(this, os);
|
||||
break;
|
||||
|
||||
case TaskReturnType.None:
|
||||
default:
|
||||
result = method.Invoke(this, os);
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
namespace ThingsGateway.Foundation.Rpc
|
||||
{
|
||||
/// <summary>
|
||||
/// 标识该接口将自动生成调用的扩展方法静态类
|
||||
/// 标识该接口将自动生成调用的代理类
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Interface, Inherited = false, AllowMultiple = false)]
|
||||
public sealed class GeneratorRpcProxyAttribute : Attribute
|
||||
@@ -39,7 +39,7 @@ namespace ThingsGateway.Foundation.Rpc
|
||||
public string Namespace { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 生成的类名,不要包含“I”,生成接口时会自动家。
|
||||
/// 生成的类名,不要包含“I”,生成接口时会自动添加。
|
||||
/// </summary>
|
||||
public string ClassName { get; set; }
|
||||
|
||||
@@ -48,11 +48,6 @@ namespace ThingsGateway.Foundation.Rpc
|
||||
/// </summary>
|
||||
public CodeGeneratorFlag GeneratorFlag { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 函数标识
|
||||
/// </summary>
|
||||
public MethodFlags MethodFlags { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 继承接口
|
||||
/// </summary>
|
||||
|
||||
@@ -39,7 +39,6 @@ namespace ThingsGateway.Foundation.Rpc
|
||||
/// </summary>
|
||||
public RpcAttribute()
|
||||
{
|
||||
this.MethodFlags = MethodFlags.None;
|
||||
this.Exceptions.Add(typeof(TimeoutException), "调用超时");
|
||||
this.Exceptions.Add(typeof(RpcInvokeException), "Rpc调用异常");
|
||||
this.Exceptions.Add(typeof(Exception), "其他异常");
|
||||
@@ -72,11 +71,6 @@ namespace ThingsGateway.Foundation.Rpc
|
||||
/// </summary>
|
||||
public string InvokeKey { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 函数标识
|
||||
/// </summary>
|
||||
public MethodFlags MethodFlags { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否仅以函数名调用,当为True是,调用时仅需要传入方法名即可。
|
||||
/// </summary>
|
||||
@@ -122,25 +116,25 @@ namespace ThingsGateway.Foundation.Rpc
|
||||
|
||||
codeString.Append("public static ");
|
||||
codeString.Append(this.GetReturn(methodInstance, false));
|
||||
codeString.Append(" ");
|
||||
codeString.Append(' ');
|
||||
codeString.Append(this.GetMethodName(methodInstance, false));
|
||||
codeString.Append("<TClient>(");//方法参数
|
||||
|
||||
codeString.Append($"this TClient client");
|
||||
|
||||
codeString.Append(",");
|
||||
codeString.Append(',');
|
||||
for (var i = 0; i < parametersStr.Count; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
codeString.Append(",");
|
||||
codeString.Append(',');
|
||||
}
|
||||
|
||||
codeString.Append(parametersStr[i]);
|
||||
}
|
||||
if (parametersStr.Count > 0)
|
||||
{
|
||||
codeString.Append(",");
|
||||
codeString.Append(',');
|
||||
}
|
||||
codeString.Append(this.GetInvokeOption());
|
||||
codeString.AppendLine(") where TClient:");
|
||||
@@ -149,7 +143,7 @@ namespace ThingsGateway.Foundation.Rpc
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
codeString.Append(",");
|
||||
codeString.Append(',');
|
||||
}
|
||||
|
||||
codeString.Append(InterfaceTypes[i].FullName);
|
||||
@@ -159,7 +153,7 @@ namespace ThingsGateway.Foundation.Rpc
|
||||
if (parametersStr.Count > 0)
|
||||
{
|
||||
codeString.Append($"object[] parameters = new object[]");
|
||||
codeString.Append("{");
|
||||
codeString.Append('{');
|
||||
|
||||
foreach (var parameter in parameters)
|
||||
{
|
||||
@@ -173,7 +167,7 @@ namespace ThingsGateway.Foundation.Rpc
|
||||
}
|
||||
if (parameter != parameters[parameters.Length - 1])
|
||||
{
|
||||
codeString.Append(",");
|
||||
codeString.Append(',');
|
||||
}
|
||||
}
|
||||
codeString.AppendLine("};");
|
||||
@@ -181,13 +175,13 @@ namespace ThingsGateway.Foundation.Rpc
|
||||
if (isOut || isRef)
|
||||
{
|
||||
codeString.Append($"Type[] types = new Type[]");
|
||||
codeString.Append("{");
|
||||
codeString.Append('{');
|
||||
foreach (var parameter in parameters)
|
||||
{
|
||||
codeString.Append($"typeof({this.GetProxyParameterName(parameter)})");
|
||||
if (parameter != parameters[parameters.Length - 1])
|
||||
{
|
||||
codeString.Append(",");
|
||||
codeString.Append(',');
|
||||
}
|
||||
}
|
||||
codeString.AppendLine("};");
|
||||
@@ -199,7 +193,7 @@ namespace ThingsGateway.Foundation.Rpc
|
||||
if (parametersStr.Count == 0)
|
||||
{
|
||||
codeString.Append(string.Format("{0} returnData=({0})client.Invoke", this.GetProxyParameterName(methodInstance.Info.ReturnParameter)));
|
||||
codeString.Append("(");
|
||||
codeString.Append('(');
|
||||
codeString.Append(string.Format("typeof({0}),", this.GetProxyParameterName(methodInstance.Info.ReturnParameter)));
|
||||
codeString.Append($"\"{this.GetInvokenKey(methodInstance)}\"");
|
||||
codeString.AppendLine(",invokeOption, null);");
|
||||
@@ -207,7 +201,7 @@ namespace ThingsGateway.Foundation.Rpc
|
||||
else if (isOut || isRef)
|
||||
{
|
||||
codeString.Append(string.Format("{0} returnData=({0})client.Invoke", this.GetProxyParameterName(methodInstance.Info.ReturnParameter)));
|
||||
codeString.Append("(");
|
||||
codeString.Append('(');
|
||||
codeString.Append(string.Format("typeof({0}),", this.GetProxyParameterName(methodInstance.Info.ReturnParameter)));
|
||||
codeString.Append($"\"{this.GetInvokenKey(methodInstance)}\"");
|
||||
codeString.AppendLine(",invokeOption,ref parameters,types);");
|
||||
@@ -215,7 +209,7 @@ namespace ThingsGateway.Foundation.Rpc
|
||||
else
|
||||
{
|
||||
codeString.Append(string.Format("{0} returnData=({0})client.Invoke", this.GetProxyParameterName(methodInstance.Info.ReturnParameter)));
|
||||
codeString.Append("(");
|
||||
codeString.Append('(');
|
||||
codeString.Append(string.Format("typeof({0}),", this.GetProxyParameterName(methodInstance.Info.ReturnParameter)));
|
||||
codeString.Append($"\"{this.GetInvokenKey(methodInstance)}\"");
|
||||
codeString.AppendLine(",invokeOption, parameters);");
|
||||
@@ -275,12 +269,12 @@ namespace ThingsGateway.Foundation.Rpc
|
||||
}
|
||||
|
||||
//以下生成异步
|
||||
if (this.GeneratorFlag.HasFlag(CodeGeneratorFlag.ExtensionAsync) && !isOut && !isRef)//没有out或者ref
|
||||
if (this.GeneratorFlag.HasFlag(CodeGeneratorFlag.ExtensionAsync) /*&& !isOut && !isRef*/)
|
||||
{
|
||||
codeString.AppendLine("///<summary>");
|
||||
codeString.AppendLine($"///{description}");
|
||||
codeString.AppendLine("///</summary>");
|
||||
if (methodInstance.HasReturn)
|
||||
if (methodInstance.HasReturn && !isOut && !isRef)
|
||||
{
|
||||
codeString.Append("public static async ");
|
||||
}
|
||||
@@ -289,24 +283,24 @@ namespace ThingsGateway.Foundation.Rpc
|
||||
codeString.Append("public static ");
|
||||
}
|
||||
codeString.Append(this.GetReturn(methodInstance, true));
|
||||
codeString.Append(" ");
|
||||
codeString.Append(' ');
|
||||
codeString.Append(this.GetMethodName(methodInstance, true));
|
||||
codeString.Append("<TClient>(");//方法参数
|
||||
|
||||
codeString.Append($"this TClient client");
|
||||
|
||||
codeString.Append(",");
|
||||
codeString.Append(',');
|
||||
for (var i = 0; i < parametersStr.Count; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
codeString.Append(",");
|
||||
codeString.Append(',');
|
||||
}
|
||||
codeString.Append(parametersStr[i]);
|
||||
}
|
||||
if (parametersStr.Count > 0)
|
||||
{
|
||||
codeString.Append(",");
|
||||
codeString.Append(',');
|
||||
}
|
||||
codeString.Append(this.GetInvokeOption());
|
||||
codeString.AppendLine(") where TClient:");
|
||||
@@ -315,7 +309,7 @@ namespace ThingsGateway.Foundation.Rpc
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
codeString.Append(",");
|
||||
codeString.Append(',');
|
||||
}
|
||||
|
||||
codeString.Append(InterfaceTypes[i].FullName);
|
||||
@@ -326,16 +320,39 @@ namespace ThingsGateway.Foundation.Rpc
|
||||
if (parametersStr.Count > 0)
|
||||
{
|
||||
codeString.Append($"object[] parameters = new object[]");
|
||||
codeString.Append("{");
|
||||
codeString.Append('{');
|
||||
|
||||
foreach (var parameter in parameters)
|
||||
{
|
||||
codeString.Append(parameter.Name);
|
||||
if (parameter.ParameterType.Name.Contains("&") && parameter.IsOut)
|
||||
{
|
||||
codeString.Append($"default({this.GetProxyParameterName(parameter)})");
|
||||
}
|
||||
else
|
||||
{
|
||||
codeString.Append(parameter.Name);
|
||||
}
|
||||
if (parameter != parameters[parameters.Length - 1])
|
||||
{
|
||||
codeString.Append(",");
|
||||
codeString.Append(',');
|
||||
}
|
||||
}
|
||||
codeString.AppendLine("};");
|
||||
|
||||
if (isOut || isRef)
|
||||
{
|
||||
codeString.Append($"Type[] types = new Type[]");
|
||||
codeString.Append('{');
|
||||
foreach (var parameter in parameters)
|
||||
{
|
||||
codeString.Append($"typeof({this.GetProxyParameterName(parameter)})");
|
||||
if (parameter != parameters[parameters.Length - 1])
|
||||
{
|
||||
codeString.Append(',');
|
||||
}
|
||||
}
|
||||
codeString.AppendLine("};");
|
||||
}
|
||||
}
|
||||
|
||||
if (methodInstance.HasReturn)
|
||||
@@ -343,15 +360,23 @@ namespace ThingsGateway.Foundation.Rpc
|
||||
if (parametersStr.Count == 0)
|
||||
{
|
||||
codeString.Append(string.Format("return ({0}) await client.InvokeAsync", this.GetProxyParameterName(methodInstance.Info.ReturnParameter)));
|
||||
codeString.Append("(");
|
||||
codeString.Append('(');
|
||||
codeString.Append(string.Format("typeof({0}),", this.GetProxyParameterName(methodInstance.Info.ReturnParameter)));
|
||||
codeString.Append($"\"{this.GetInvokenKey(methodInstance)}\"");
|
||||
codeString.AppendLine(",invokeOption, null);");
|
||||
}
|
||||
else if (isOut || isRef)
|
||||
{
|
||||
codeString.Append(string.Format("{0} returnData=({0})client.Invoke", this.GetProxyParameterName(methodInstance.Info.ReturnParameter)));
|
||||
codeString.Append('(');
|
||||
codeString.Append(string.Format("typeof({0}),", this.GetProxyParameterName(methodInstance.Info.ReturnParameter)));
|
||||
codeString.Append($"\"{this.GetInvokenKey(methodInstance)}\"");
|
||||
codeString.AppendLine(",invokeOption,ref parameters,types);");
|
||||
}
|
||||
else
|
||||
{
|
||||
codeString.Append(string.Format("return ({0}) await client.InvokeAsync", this.GetProxyParameterName(methodInstance.Info.ReturnParameter)));
|
||||
codeString.Append("(");
|
||||
codeString.Append('(');
|
||||
codeString.Append(string.Format("typeof({0}),", this.GetProxyParameterName(methodInstance.Info.ReturnParameter)));
|
||||
codeString.Append($"\"{this.GetInvokenKey(methodInstance)}\"");
|
||||
codeString.AppendLine(",invokeOption, parameters);");
|
||||
@@ -365,6 +390,12 @@ namespace ThingsGateway.Foundation.Rpc
|
||||
codeString.Append($"\"{this.GetInvokenKey(methodInstance)}\"");
|
||||
codeString.AppendLine(",invokeOption, null);");
|
||||
}
|
||||
else if (isOut || isRef)
|
||||
{
|
||||
codeString.Append("client.Invoke(");
|
||||
codeString.Append($"\"{this.GetInvokenKey(methodInstance)}\"");
|
||||
codeString.AppendLine(",invokeOption,ref parameters,types);");
|
||||
}
|
||||
else
|
||||
{
|
||||
codeString.Append("return client.InvokeAsync(");
|
||||
@@ -372,6 +403,43 @@ namespace ThingsGateway.Foundation.Rpc
|
||||
codeString.AppendLine(",invokeOption, parameters);");
|
||||
}
|
||||
}
|
||||
|
||||
if (isOut || isRef)
|
||||
{
|
||||
codeString.AppendLine("if(parameters!=null)");
|
||||
codeString.AppendLine("{");
|
||||
for (var i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
codeString.AppendLine(string.Format("{0}=({1})parameters[{2}];", parameters[i].Name, this.GetProxyParameterName(parameters[i]), i));
|
||||
}
|
||||
codeString.AppendLine("}");
|
||||
if (isOut)
|
||||
{
|
||||
codeString.AppendLine("else");
|
||||
codeString.AppendLine("{");
|
||||
for (var i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
if (parameters[i].IsOut)
|
||||
{
|
||||
codeString.AppendLine(string.Format("{0}=default({1});", parameters[i].Name, this.GetProxyParameterName(parameters[i])));
|
||||
}
|
||||
}
|
||||
codeString.AppendLine("}");
|
||||
}
|
||||
}
|
||||
|
||||
if (isOut || isRef)
|
||||
{
|
||||
if (methodInstance.HasReturn)
|
||||
{
|
||||
codeString.AppendLine(string.Format("return Task.FromResult<{0}>(returnData);", this.GetProxyParameterName(methodInstance.Info.ReturnParameter)));
|
||||
}
|
||||
else
|
||||
{
|
||||
codeString.AppendLine(string.Format("return EasyTask.CompletedTask;"));
|
||||
}
|
||||
}
|
||||
|
||||
codeString.AppendLine("}");
|
||||
}
|
||||
return codeString.ToString();
|
||||
@@ -409,21 +477,21 @@ namespace ThingsGateway.Foundation.Rpc
|
||||
|
||||
codeString.Append("public ");
|
||||
codeString.Append(this.GetReturn(methodInstance, false));
|
||||
codeString.Append(" ");
|
||||
codeString.Append(' ');
|
||||
codeString.Append(this.GetMethodName(methodInstance, false));
|
||||
codeString.Append("(");//方法参数
|
||||
codeString.Append('(');//方法参数
|
||||
|
||||
for (var i = 0; i < parametersStr.Count; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
codeString.Append(",");
|
||||
codeString.Append(',');
|
||||
}
|
||||
codeString.Append(parametersStr[i]);
|
||||
}
|
||||
if (parametersStr.Count > 0)
|
||||
{
|
||||
codeString.Append(",");
|
||||
codeString.Append(',');
|
||||
}
|
||||
codeString.Append(this.GetInvokeOption());
|
||||
codeString.AppendLine(")");
|
||||
@@ -438,7 +506,7 @@ namespace ThingsGateway.Foundation.Rpc
|
||||
if (parametersStr.Count > 0)
|
||||
{
|
||||
codeString.Append($"object[] parameters = new object[]");
|
||||
codeString.Append("{");
|
||||
codeString.Append('{');
|
||||
|
||||
foreach (var parameter in parameters)
|
||||
{
|
||||
@@ -452,7 +520,7 @@ namespace ThingsGateway.Foundation.Rpc
|
||||
}
|
||||
if (parameter != parameters[parameters.Length - 1])
|
||||
{
|
||||
codeString.Append(",");
|
||||
codeString.Append(',');
|
||||
}
|
||||
}
|
||||
codeString.AppendLine("};");
|
||||
@@ -460,13 +528,13 @@ namespace ThingsGateway.Foundation.Rpc
|
||||
if (isOut || isRef)
|
||||
{
|
||||
codeString.Append($"Type[] types = new Type[]");
|
||||
codeString.Append("{");
|
||||
codeString.Append('{');
|
||||
foreach (var parameter in parameters)
|
||||
{
|
||||
codeString.Append($"typeof({this.GetProxyParameterName(parameter)})");
|
||||
if (parameter != parameters[parameters.Length - 1])
|
||||
{
|
||||
codeString.Append(",");
|
||||
codeString.Append(',');
|
||||
}
|
||||
}
|
||||
codeString.AppendLine("};");
|
||||
@@ -478,7 +546,7 @@ namespace ThingsGateway.Foundation.Rpc
|
||||
if (parametersStr.Count == 0)
|
||||
{
|
||||
codeString.Append(string.Format("{0} returnData=({0})Client.Invoke", this.GetProxyParameterName(methodInstance.Info.ReturnParameter)));
|
||||
codeString.Append("(");
|
||||
codeString.Append('(');
|
||||
codeString.Append(string.Format("typeof({0}),", this.GetProxyParameterName(methodInstance.Info.ReturnParameter)));
|
||||
codeString.Append($"\"{this.GetInvokenKey(methodInstance)}\"");
|
||||
codeString.AppendLine(",invokeOption, null);");
|
||||
@@ -554,12 +622,12 @@ namespace ThingsGateway.Foundation.Rpc
|
||||
}
|
||||
|
||||
//以下生成异步
|
||||
if (this.GeneratorFlag.HasFlag(CodeGeneratorFlag.InstanceAsync) && !isOut && !isRef)//没有out或者ref
|
||||
if (this.GeneratorFlag.HasFlag(CodeGeneratorFlag.InstanceAsync))
|
||||
{
|
||||
codeString.AppendLine("///<summary>");
|
||||
codeString.AppendLine($"///{description}");
|
||||
codeString.AppendLine("///</summary>");
|
||||
if (methodInstance.HasReturn)
|
||||
if (methodInstance.HasReturn && (!isOut && !isRef))
|
||||
{
|
||||
codeString.Append("public async ");
|
||||
}
|
||||
@@ -568,21 +636,21 @@ namespace ThingsGateway.Foundation.Rpc
|
||||
codeString.Append("public ");
|
||||
}
|
||||
codeString.Append(this.GetReturn(methodInstance, true));
|
||||
codeString.Append(" ");
|
||||
codeString.Append(' ');
|
||||
codeString.Append(this.GetMethodName(methodInstance, true));
|
||||
codeString.Append("(");//方法参数
|
||||
codeString.Append('(');//方法参数
|
||||
|
||||
for (var i = 0; i < parametersStr.Count; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
codeString.Append(",");
|
||||
codeString.Append(',');
|
||||
}
|
||||
codeString.Append(parametersStr[i]);
|
||||
}
|
||||
if (parametersStr.Count > 0)
|
||||
{
|
||||
codeString.Append(",");
|
||||
codeString.Append(',');
|
||||
}
|
||||
codeString.Append(this.GetInvokeOption());
|
||||
codeString.AppendLine(")");
|
||||
@@ -597,16 +665,39 @@ namespace ThingsGateway.Foundation.Rpc
|
||||
if (parametersStr.Count > 0)
|
||||
{
|
||||
codeString.Append($"object[] parameters = new object[]");
|
||||
codeString.Append("{");
|
||||
codeString.Append('{');
|
||||
|
||||
foreach (var parameter in parameters)
|
||||
{
|
||||
codeString.Append(parameter.Name);
|
||||
if (parameter.ParameterType.Name.Contains("&") && parameter.IsOut)
|
||||
{
|
||||
codeString.Append($"default({this.GetProxyParameterName(parameter)})");
|
||||
}
|
||||
else
|
||||
{
|
||||
codeString.Append(parameter.Name);
|
||||
}
|
||||
if (parameter != parameters[parameters.Length - 1])
|
||||
{
|
||||
codeString.Append(",");
|
||||
codeString.Append(',');
|
||||
}
|
||||
}
|
||||
codeString.AppendLine("};");
|
||||
|
||||
if (isOut || isRef)
|
||||
{
|
||||
codeString.Append($"Type[] types = new Type[]");
|
||||
codeString.Append('{');
|
||||
foreach (var parameter in parameters)
|
||||
{
|
||||
codeString.Append($"typeof({this.GetProxyParameterName(parameter)})");
|
||||
if (parameter != parameters[parameters.Length - 1])
|
||||
{
|
||||
codeString.Append(',');
|
||||
}
|
||||
}
|
||||
codeString.AppendLine("};");
|
||||
}
|
||||
}
|
||||
|
||||
if (methodInstance.HasReturn)
|
||||
@@ -614,15 +705,23 @@ namespace ThingsGateway.Foundation.Rpc
|
||||
if (parametersStr.Count == 0)
|
||||
{
|
||||
codeString.Append(string.Format("return ({0}) await Client.InvokeAsync", this.GetProxyParameterName(methodInstance.Info.ReturnParameter)));
|
||||
codeString.Append("(");
|
||||
codeString.Append('(');
|
||||
codeString.Append(string.Format("typeof({0}),", this.GetProxyParameterName(methodInstance.Info.ReturnParameter)));
|
||||
codeString.Append($"\"{this.GetInvokenKey(methodInstance)}\"");
|
||||
codeString.AppendLine(",invokeOption, null);");
|
||||
}
|
||||
else if (isOut || isRef)
|
||||
{
|
||||
codeString.Append(string.Format("{0} returnData=({0})Client.Invoke", this.GetProxyParameterName(methodInstance.Info.ReturnParameter)));
|
||||
codeString.Append('(');
|
||||
codeString.Append(string.Format("typeof({0}),", this.GetProxyParameterName(methodInstance.Info.ReturnParameter)));
|
||||
codeString.Append($"\"{this.GetInvokenKey(methodInstance)}\"");
|
||||
codeString.AppendLine(",invokeOption,ref parameters,types);");
|
||||
}
|
||||
else
|
||||
{
|
||||
codeString.Append(string.Format("return ({0}) await Client.InvokeAsync", this.GetProxyParameterName(methodInstance.Info.ReturnParameter)));
|
||||
codeString.Append("(");
|
||||
codeString.Append('(');
|
||||
codeString.Append(string.Format("typeof({0}),", this.GetProxyParameterName(methodInstance.Info.ReturnParameter)));
|
||||
codeString.Append($"\"{this.GetInvokenKey(methodInstance)}\"");
|
||||
codeString.AppendLine(",invokeOption, parameters);");
|
||||
@@ -636,6 +735,12 @@ namespace ThingsGateway.Foundation.Rpc
|
||||
codeString.Append($"\"{this.GetInvokenKey(methodInstance)}\"");
|
||||
codeString.AppendLine(",invokeOption, null);");
|
||||
}
|
||||
else if (isOut || isRef)
|
||||
{
|
||||
codeString.Append("Client.Invoke(");
|
||||
codeString.Append($"\"{this.GetInvokenKey(methodInstance)}\"");
|
||||
codeString.AppendLine(",invokeOption,ref parameters,types);");
|
||||
}
|
||||
else
|
||||
{
|
||||
codeString.Append("return Client.InvokeAsync(");
|
||||
@@ -643,8 +748,46 @@ namespace ThingsGateway.Foundation.Rpc
|
||||
codeString.AppendLine(",invokeOption, parameters);");
|
||||
}
|
||||
}
|
||||
|
||||
if (isOut || isRef)
|
||||
{
|
||||
codeString.AppendLine("if(parameters!=null)");
|
||||
codeString.AppendLine("{");
|
||||
for (var i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
codeString.AppendLine(string.Format("{0}=({1})parameters[{2}];", parameters[i].Name, this.GetProxyParameterName(parameters[i]), i));
|
||||
}
|
||||
codeString.AppendLine("}");
|
||||
if (isOut)
|
||||
{
|
||||
codeString.AppendLine("else");
|
||||
codeString.AppendLine("{");
|
||||
for (var i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
if (parameters[i].IsOut)
|
||||
{
|
||||
codeString.AppendLine(string.Format("{0}=default({1});", parameters[i].Name, this.GetProxyParameterName(parameters[i])));
|
||||
}
|
||||
}
|
||||
codeString.AppendLine("}");
|
||||
}
|
||||
}
|
||||
|
||||
if (isOut || isRef)
|
||||
{
|
||||
if (methodInstance.HasReturn)
|
||||
{
|
||||
codeString.AppendLine(string.Format("return Task.FromResult<{0}>(returnData);", this.GetProxyParameterName(methodInstance.Info.ReturnParameter)));
|
||||
}
|
||||
else
|
||||
{
|
||||
codeString.AppendLine(string.Format("return EasyTask.CompletedTask;"));
|
||||
}
|
||||
}
|
||||
codeString.AppendLine("}");
|
||||
}
|
||||
|
||||
|
||||
return codeString.ToString();
|
||||
}
|
||||
|
||||
@@ -669,26 +812,26 @@ namespace ThingsGateway.Foundation.Rpc
|
||||
}
|
||||
|
||||
codeString.Append(this.GetReturn(methodInstance, false));
|
||||
codeString.Append(" ");
|
||||
codeString.Append(' ');
|
||||
codeString.Append(this.GetMethodName(methodInstance, false));
|
||||
codeString.Append("(");//方法参数
|
||||
codeString.Append('(');//方法参数
|
||||
for (var i = 0; i < parameters.Count; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
codeString.Append(",");
|
||||
codeString.Append(',');
|
||||
}
|
||||
codeString.Append(parameters[i]);
|
||||
}
|
||||
if (parameters.Count > 0)
|
||||
{
|
||||
codeString.Append(",");
|
||||
codeString.Append(',');
|
||||
}
|
||||
codeString.Append(this.GetInvokeOption());
|
||||
codeString.AppendLine(");");
|
||||
}
|
||||
|
||||
if (this.GeneratorFlag.HasFlag(CodeGeneratorFlag.InterfaceAsync) && !isOut && !isRef)//没有out或者ref
|
||||
if (this.GeneratorFlag.HasFlag(CodeGeneratorFlag.InterfaceAsync))
|
||||
{
|
||||
codeString.AppendLine("///<summary>");
|
||||
codeString.AppendLine($"///{description}");
|
||||
@@ -699,21 +842,21 @@ namespace ThingsGateway.Foundation.Rpc
|
||||
}
|
||||
|
||||
codeString.Append(this.GetReturn(methodInstance, true));
|
||||
codeString.Append(" ");
|
||||
codeString.Append(' ');
|
||||
codeString.Append(this.GetMethodName(methodInstance, true));
|
||||
codeString.Append("(");//方法参数
|
||||
codeString.Append('(');//方法参数
|
||||
|
||||
for (var i = 0; i < parameters.Count; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
codeString.Append(",");
|
||||
codeString.Append(',');
|
||||
}
|
||||
codeString.Append(parameters[i]);
|
||||
}
|
||||
if (parameters.Count > 0)
|
||||
{
|
||||
codeString.Append(",");
|
||||
codeString.Append(',');
|
||||
}
|
||||
codeString.Append(this.GetInvokeOption());
|
||||
codeString.AppendLine(");");
|
||||
@@ -774,7 +917,7 @@ namespace ThingsGateway.Foundation.Rpc
|
||||
isOut = false;
|
||||
isRef = false;
|
||||
|
||||
if (methodInstance.MethodFlags.HasFlag(MethodFlags.IncludeCallContext))
|
||||
if (methodInstance.IncludeCallContext)
|
||||
{
|
||||
var infos = new List<ParameterInfo>(methodInstance.Parameters);
|
||||
infos.RemoveAt(0);
|
||||
|
||||